Motr  M0
pvers.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016-2020 Seagate Technology LLC and/or its Affiliates
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * For any questions about this software or licensing,
17  * please email opensource@seagate.com or cortx-questions@seagate.com.
18  *
19  */
20 
21 
28 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_CONF
29 #include "lib/trace.h"
30 
31 #include "conf/pvers.h"
32 #include "conf/cache.h" /* m0_conf_cache_lock */
33 #include "conf/obj_ops.h" /* m0_conf_dir_tl */
34 #include "conf/walk.h"
35 #include "conf/glob.h"
36 #include "fd/fd.h" /* m0_fd_tolerance_check */
37 #include "conf/objs/common.h" /* m0_conf_dir_new */
38 #include "lib/combinations.h" /* m0_combination_index */
39 #include "lib/memory.h" /* M0_ALLOC_ARR */
40 
41 #define CONF_PVER_VECTOR_LOG(owner, fid, vector) \
42  M0_LOG(M0_DEBUG, owner"="FID_F" "#vector"=[%u %u %u %u %u]", fid, \
43  vector[M0_CONF_PVER_LVL_SITES], \
44  vector[M0_CONF_PVER_LVL_RACKS], \
45  vector[M0_CONF_PVER_LVL_ENCLS], \
46  vector[M0_CONF_PVER_LVL_CTRLS], \
47  vector[M0_CONF_PVER_LVL_DRIVES])
48 
49 enum {
53 };
54 
56 struct arr_int {
57  uint32_t ai_count;
58  int *ai_elems;
59 };
60 
61 struct arr_int_pos {
62  struct arr_int ap_arr;
63  uint32_t ap_pos;
64 };
65 
66 static int conf_pver_formulate(const struct m0_conf_pver *fpver,
67  struct m0_conf_pver **out);
68 static int conf_pver_formulaic_base(const struct m0_conf_pver *fpver,
69  struct m0_conf_pver **out);
70 static int conf_pver_objvs_count(struct m0_conf_pver *base, uint32_t *out);
71 static int conf_pver_virtual_create(const struct m0_fid *fid,
72  struct m0_conf_pver *base,
73  const uint32_t *allowance,
74  struct arr_int *failed,
75  struct m0_conf_pver **out);
76 static int conf_pver_failures_cid(struct m0_conf_pver *base, uint64_t *out);
77 static void conf_pver_subtree_delete(struct m0_conf_obj *obj);
78 static int conf_pver_recd_build(struct m0_conf_obj *obj, void *args);
79 
80 static int conf_pver_formulaic_find_locked(uint32_t fpver_id,
81  const struct m0_conf_root *root,
82  const struct m0_conf_pver **out)
83 {
84  enum { CONF_GLOB_BATCH = 16 }; /* arbitrary number */
85  struct m0_conf_glob glob;
86  const struct m0_conf_obj *objs[CONF_GLOB_BATCH];
87  const struct m0_conf_pver *pver;
88  int i;
89  int rc;
90 
92  M0_CONF_ROOT_POOLS_FID, M0_CONF_ANY_FID,
93  M0_CONF_POOL_PVERS_FID, M0_CONF_ANY_FID);
94  while ((rc = m0_conf_glob(&glob, ARRAY_SIZE(objs), objs)) > 0) {
95  for (i = 0; i < rc; ++i) {
96  pver = M0_CONF_CAST(objs[i], m0_conf_pver);
97  if (pver->pv_kind == M0_CONF_PVER_FORMULAIC &&
98  pver->pv_u.formulaic.pvf_id == fpver_id) {
99  *out = pver;
100  return M0_RC(0);
101  }
102  }
103  }
104  return rc == 0 ? M0_ERR_INFO(-ENOENT, "Formulaic pver with id=%u"
105  " is missing", fpver_id) : M0_ERR(rc);
106 }
107 
109 {
110  const struct m0_conf_obj *obj;
111  struct m0_conf_pver *pver;
112  int rc = 0;
113 
114  m0_tl_for (m0_conf_dir, &pool->pl_pvers->cd_items, obj) {
116  if (pver->pv_kind == M0_CONF_PVER_ACTUAL) {
117  M0_SET_ARR0(pver->pv_u.subtree.pvs_recd);
119  pver->pv_u.subtree.pvs_recd);
120  break;
121  }
122  } m0_tl_endfor;
123  return M0_RC(rc);
124 }
125 
126 static int conf_pver_find_locked(const struct m0_conf_pool *pool,
127  const struct m0_fid *pver_to_skip,
128  struct m0_conf_pver **out)
129 {
130  const struct m0_conf_obj *obj;
131  struct m0_conf_pver *pver;
132  int rc;
133 
134  M0_ENTRY("pool="FID_F, FID_P(&pool->pl_obj.co_id));
135 
137  if (rc != 0)
138  return M0_ERR_INFO(rc, "Recd update failed for pool "FID_F,
139  FID_P(&pool->pl_obj.co_id));
140  m0_tl_for (m0_conf_dir, &pool->pl_pvers->cd_items, obj) {
142  M0_LOG(M0_DEBUG, "pver="FID_F, FID_P(&pver->pv_obj.co_id));
143  if (pver_to_skip != NULL &&
144  m0_fid_eq(&pver->pv_obj.co_id, pver_to_skip)) {
145  M0_LOG(M0_INFO, "Skipping "FID_F, FID_P(pver_to_skip));
146  continue;
147  }
149  continue;
150  if (pver->pv_kind == M0_CONF_PVER_ACTUAL) {
151  *out = pver;
152  return M0_RC(0);
153  }
154  return M0_RC(conf_pver_formulate(pver, out));
155  } m0_tl_endfor;
156  return M0_ERR_INFO(-ENOENT, "No suitable pver is found at pool "FID_F,
157  FID_P(&pool->pl_obj.co_id));
158 }
159 
160 static int conf_pver_find_by_fid_locked(const struct m0_fid *fid,
161  const struct m0_conf_root *root,
162  struct m0_conf_pver **out)
163 {
164  struct m0_conf_obj *obj;
165  enum m0_conf_pver_kind kind;
166  uint64_t container;
167  uint64_t key;
168  const struct m0_conf_pver *fpver;
169  struct m0_conf_pver *base = NULL;
170  uint32_t nr_total;
171  struct arr_int failed;
172  int rc;
173 
175 
177  if (obj != NULL) {
179  M0_ASSERT((*out)->pv_kind != M0_CONF_PVER_FORMULAIC);
180  return M0_RC(0);
181  }
182  rc = m0_conf_pver_fid_read(fid, &kind, &container, &key);
183  if (rc != 0)
184  return M0_ERR(rc);
185  if (kind == M0_CONF_PVER_ACTUAL)
186  return M0_ERR_INFO(-ENOENT, "Actual pver is missing: "FID_F,
187  FID_P(fid));
190  conf_pver_formulaic_base(fpver, &base) ?:
191  conf_pver_objvs_count(base, &nr_total);
192  if (rc != 0)
193  return M0_ERR(rc);
194  failed.ai_count = m0_reduce(i, M0_CONF_PVER_HEIGHT, 0,
195  + fpver->pv_u.formulaic.pvf_allowance[i]);
196  M0_ASSERT(failed.ai_count > 0);
197  M0_ALLOC_ARR(failed.ai_elems, failed.ai_count);
198  if (failed.ai_elems == NULL)
199  return M0_ERR(-ENOMEM);
200  m0_combination_inverse(key, nr_total, failed.ai_count, failed.ai_elems);
202  fid, base, fpver->pv_u.formulaic.pvf_allowance, &failed, out);
203  m0_free(failed.ai_elems);
204  return M0_RC(rc);
205 }
206 
207 M0_INTERNAL int m0_conf_pver_find(const struct m0_conf_pool *pool,
208  const struct m0_fid *pver_to_skip,
209  struct m0_conf_pver **out)
210 {
211  int rc;
212 
213  m0_conf_cache_lock(pool->pl_obj.co_cache);
214  rc = conf_pver_find_locked(pool, pver_to_skip, out);
215  m0_conf_cache_unlock(pool->pl_obj.co_cache);
216  return rc;
217 }
218 
219 M0_INTERNAL int m0_conf_pver_find_by_fid(const struct m0_fid *fid,
220  const struct m0_conf_root *root,
221  struct m0_conf_pver **out)
222 {
223  int rc;
224 
228  return rc;
229 }
230 
231 M0_INTERNAL int m0_conf_pver_formulaic_find(uint32_t fpver_id,
232  const struct m0_conf_root *root,
233  const struct m0_conf_pver **out)
234 {
235  int rc;
236 
240  return rc;
241 }
242 
243 M0_INTERNAL int
245  const struct m0_conf_root *root,
246  const struct m0_conf_pver **out)
247 {
248  uint64_t cont;
249 
250  M0_ENTRY("virtual="FID_F, FID_P(&virtual->pv_obj.co_id));
251  M0_PRE(virtual->pv_kind == M0_CONF_PVER_VIRTUAL);
252 
253  return M0_RC(m0_conf_pver_fid_read(&virtual->pv_obj.co_id, NULL, &cont,
254  NULL) ?:
256  /* formulaic pver id; see m0_conf_pver_fid() */
257  cont & 0xffffffff,
258  root, out));
259 }
260 
262 static int conf_pver_formulaic_base(const struct m0_conf_pver *fpver,
263  struct m0_conf_pver **out)
264 {
265  const struct m0_conf_obj *base;
266 
268 
270  &fpver->pv_u.formulaic.pvf_base);
271  if (base == NULL)
272  return M0_ERR_INFO(-ENOENT, "Base "FID_F" of formulaic pver "
273  FID_F" is missing",
274  FID_P(&fpver->pv_u.formulaic.pvf_base),
275  FID_P(&fpver->pv_obj.co_id));
277  M0_POST((*out)->pv_kind == M0_CONF_PVER_ACTUAL);
278  return M0_RC(0);
279 }
280 
281 M0_INTERNAL bool m0_conf_pver_is_clean(const struct m0_conf_pver *pver)
282 {
283  struct m0_conf_pver *base = NULL;
284  const uint32_t *recd;
285  const uint32_t *allowance;
286 
287  M0_ENTRY("pver=%p "FID_F, pver, FID_P(&pver->pv_obj.co_id));
288 
289  if (pver->pv_kind == M0_CONF_PVER_ACTUAL) {
290  recd = pver->pv_u.subtree.pvs_recd;
291  CONF_PVER_VECTOR_LOG("actual", FID_P(&pver->pv_obj.co_id),
292  recd);
293  return M0_RC(M0_IS0(&pver->pv_u.subtree.pvs_recd));
294  }
296  if (conf_pver_formulaic_base(pver, &base) != 0)
297  return M0_RC(false);
298  recd = base->pv_u.subtree.pvs_recd;
299  allowance = pver->pv_u.formulaic.pvf_allowance;
300  CONF_PVER_VECTOR_LOG("fpver", FID_P(&pver->pv_obj.co_id), allowance);
301  CONF_PVER_VECTOR_LOG("base", FID_P(&base->pv_obj.co_id), recd);
303  recd[i] == allowance[i]));
304 }
305 
306 enum { CONF_PVER_FID_MASK = 0x003fffffffffffffULL };
307 
308 M0_INTERNAL struct m0_fid
309 m0_conf_pver_fid(enum m0_conf_pver_kind kind, uint64_t container, uint64_t key)
310 {
311  /*
312  * Actual/formulaic pver fid
313  * -------------------------
314  * .f_container:
315  * - 1-byte type id (0x76);
316  * - 2-bit kind (actual=0, formulaic=1);
317  * - 54-bit anything.
318  *
319  * .f_key:
320  * - 8-byte anything.
321  *
322  * Virtual pver fid
323  * ----------------
324  * .f_container:
325  * - 1-byte type id (0x76);
326  * - 2-bit kind (2);
327  * - 22-bit unused (zeros);
328  * - 4-byte formulaic pver id.
329  *
330  * .f_key:
331  * - 8-byte index of combination of failed devices in the ordered
332  * sequence of pver's devices.
333  */
334  if (kind == M0_CONF_PVER_VIRTUAL) {
335  /* formulaic pver id is 4 bytes */
336  M0_PRE((container & ~0xffffffff) == 0);
337  } else {
340  }
341  /*
342  * XXX TODO: Introduce M0_CONF_FID() macro.
343  *
344  * Use M0_CONF_FID(PVER, container, key) instead of
345  * M0_FID_TINIT('v', container, key) or
346  * M0_FID_TINIT(M0_CONF_PVER_TYPE.cot_ftype.ft_id, container, key).
347  */
349  (uint64_t)kind << 54 | container, key);
350 }
351 
352 M0_INTERNAL int m0_conf_pver_fid_read(const struct m0_fid *fid,
353  enum m0_conf_pver_kind *kind,
354  uint64_t *container, uint64_t *key)
355 {
356  enum m0_conf_pver_kind _kind;
357  uint64_t _container;
358 
360 
361  _kind = fid->f_container >> (64 - 8 - 2) & 3;
362  _container = fid->f_container & CONF_PVER_FID_MASK;
363  if (_kind > M0_CONF_PVER_VIRTUAL ||
364  (_kind == M0_CONF_PVER_VIRTUAL && (_container & ~0xffffffff) != 0))
365  return M0_ERR_INFO(-EINVAL, "Invalid pver fid: "FID_F,
366  FID_P(fid));
367  if (kind != NULL)
368  *kind = _kind;
369  if (container != NULL)
370  *container = _container;
371  if (key != NULL)
372  *key = fid->f_key;
373  return 0;
374 }
375 
378 {
380  /*
381  * .f_container:
382  * - 1-byte type id (0x6a);
383  * - 1-bit "virtual?" flag (1);
384  * - 55-bit unused (zeros).
385  *
386  * .f_key:
387  * - 8-byte value of m0_conf_cache::ca_fid_counter.
388  */
390  1ULL << (64 - 8 - 1),
391  cache->ca_fid_counter++);
392 }
393 
394 M0_INTERNAL unsigned m0_conf_pver_level(const struct m0_conf_obj *obj)
395 {
396  const struct m0_conf_obj_type *t = m0_conf_obj_type(obj);
397 
398  if (t == &M0_CONF_OBJV_TYPE) {
399  /* We may not access m0_conf_objv::cv_real of a stub. */
400  M0_ASSERT(obj->co_status == M0_CS_READY);
402  }
403  if (t == &M0_CONF_SITE_TYPE)
404  return M0_CONF_PVER_LVL_SITES;
405  if (t == &M0_CONF_RACK_TYPE)
406  return M0_CONF_PVER_LVL_RACKS;
407  if (t == &M0_CONF_ENCLOSURE_TYPE)
408  return M0_CONF_PVER_LVL_ENCLS;
409  if (t == &M0_CONF_CONTROLLER_TYPE)
410  return M0_CONF_PVER_LVL_CTRLS;
411  if (t == &M0_CONF_DRIVE_TYPE)
413  M0_IMPOSSIBLE("Bad argument: "FID_F, FID_P(&obj->co_id));
414 }
415  /* page break */
416 
418 static int
419 conf_pver_formulate(const struct m0_conf_pver *fpver, struct m0_conf_pver **out)
420 {
421  struct m0_conf_pver *base = NULL;
422  uint64_t failures_cid;
423  struct m0_fid virt_fid;
424  const struct m0_conf_obj *virt;
425  int rc;
426 
427  rc = conf_pver_formulaic_base(fpver, &base) ?:
428  conf_pver_failures_cid(base, &failures_cid);
429  if (rc != 0)
430  return M0_ERR(rc);
431 
433  fpver->pv_u.formulaic.pvf_id, failures_cid);
434  virt = m0_conf_cache_lookup(fpver->pv_obj.co_cache, &virt_fid);
435  if (virt != NULL) {
436  *out = M0_CONF_CAST(virt, m0_conf_pver);
437  M0_POST((*out)->pv_kind == M0_CONF_PVER_VIRTUAL);
438  return M0_RC(0);
439  }
441  &virt_fid, base,
442  fpver->pv_u.formulaic.pvf_allowance, NULL, out));
443 }
444 
448 };
449 
450 static int conf_pver_enumerate_w(struct m0_conf_obj *obj, void *args)
451 {
452  const bool skip_sanity_check = false;
453  struct m0_conf_objv *objv;
454  struct conf_pver_enumerate_st *st = args;
455 
457  objv = M0_CONF_CAST(obj, m0_conf_objv);
458  if (objv->cv_ix == 0) {
459  M0_ASSERT(st->est_counter == 0);
460  if (skip_sanity_check)
461  /*
462  * The subtree has been enumerated already,
463  * and we are in too much hurry to do
464  * sanity checking.
465  */
466  return M0_CW_STOP;
467  st->est_enumerated = true;
468  }
469  if (st->est_enumerated) {
470  M0_ASSERT(objv->cv_ix == st->est_counter);
471  } else {
472  M0_ASSERT(objv->cv_ix == -1);
473  objv->cv_ix = st->est_counter;
474  }
475  M0_CNT_INC(st->est_counter);
476  }
477  return M0_CW_CONTINUE;
478 }
479 
482 {
483  struct conf_pver_enumerate_st st = {0};
484  int rc;
485 
486  M0_PRE(pver->pv_kind == M0_CONF_PVER_ACTUAL);
487 
488  rc = m0_conf_walk(conf_pver_enumerate_w, &pver->pv_obj, &st);
489  M0_ASSERT(rc == 0); /* conf_objv_enumerate() cannot return error */
490 }
491 
492 static int conf_pver_objvs_count(struct m0_conf_pver *base, uint32_t *out)
493 {
494  const struct m0_conf_obj *obj;
495  const struct m0_conf_objv *objv;
496  uint32_t level = 0;
497 
499  obj = m0_conf_dir_tlist_tail(&base->pv_u.subtree.pvs_sitevs->cd_items);
500  /* rack-v, encl-v, ctrl-v, disk-v */
501  while (1) {
502  if (obj == NULL || m0_conf_obj_is_stub(obj))
503  return M0_ERR_INFO(-ENOENT, "Cannot reach the rightmost"
504  " disk-v from "FID_F"; reached"
505  " level %u",
506  FID_P(&base->pv_obj.co_id), level);
507  objv = M0_CONF_CAST(obj, m0_conf_objv);
508  if (objv->cv_children == NULL)
509  break;
510  obj = m0_conf_dir_tlist_tail(&objv->cv_children->cd_items);
511  ++level;
512  }
514  M0_ASSERT(objv->cv_ix > 0); /* guaranteed by conf_pver_enumerate() */
515  *out = 1 + (uint32_t)objv->cv_ix;
516  return M0_RC(0);
517 }
518 
519 static int conf_pver_recd_build(struct m0_conf_obj *obj, void *args)
520 {
521  uint32_t *recd = args;
522  struct m0_conf_objv *objv;
523  unsigned lvl;
524 
526  objv = M0_CONF_CAST(obj, m0_conf_objv);
527  if (objv->cv_real->co_ha_state != M0_NC_ONLINE) {
528  lvl = m0_conf_pver_level(obj);
529  M0_ASSERT(lvl != 0 && lvl < M0_CONF_PVER_HEIGHT);
530  M0_CNT_INC(recd[lvl]);
531  return M0_CW_SKIP_SUBTREE;
532  }
533  }
534  return M0_CW_CONTINUE;
535 }
536 
537 static int conf_objv_failed_fill(struct m0_conf_obj *obj, void *args)
538 {
539  struct arr_int_pos *a = args;
540  const struct m0_conf_objv *objv;
541 
542  M0_PRE(a->ap_arr.ai_count > 0 && a->ap_arr.ai_elems != NULL);
543 
545  return M0_CW_CONTINUE;
546  objv = M0_CONF_CAST(obj, m0_conf_objv);
547  if (objv->cv_real->co_ha_state == M0_NC_ONLINE)
548  return M0_CW_CONTINUE;
549  M0_ASSERT(a->ap_pos < a->ap_arr.ai_count);
550  a->ap_arr.ai_elems[a->ap_pos] = objv->cv_ix;
551  M0_CNT_INC(a->ap_pos);
552  return M0_CW_SKIP_SUBTREE;
553 }
554 
559 static int conf_pver_failures_cid(struct m0_conf_pver *base, uint64_t *out)
560 {
561  struct arr_int_pos a = { .ap_arr = {0} };
562  uint32_t nr_total;
563  int rc;
564 
565  M0_PRE(base->pv_kind == M0_CONF_PVER_ACTUAL);
566  M0_PRE(!M0_IS0(&base->pv_u.subtree.pvs_recd));
567 
568  rc = conf_pver_objvs_count(base, &nr_total);
569  if (rc != 0)
570  return M0_ERR(rc);
571  /*
572  * Count the number of non-online devices in the base pver subtree.
573  */
574  a.ap_arr.ai_count = m0_reduce(
575  i, ARRAY_SIZE(base->pv_u.subtree.pvs_recd), 0,
576  + base->pv_u.subtree.pvs_recd[i]);
578  if (a.ap_arr.ai_elems == NULL)
579  return M0_ERR(-ENOMEM);
580  /*
581  * Put indices of failed devices into the array.
582  */
583  rc = m0_conf_walk(conf_objv_failed_fill, &base->pv_obj, &a);
584  M0_ASSERT(rc == 0); /* conf_objv_failed_fill() cannot return error */
586  /*
587  * Compute index of combination of failed devices.
588  */
589  *out = (uint64_t)m0_combination_index(nr_total, a.ap_arr.ai_count,
590  a.ap_arr.ai_elems);
592  return M0_RC(0);
593 }
594 
597  const struct arr_int *bws_failed;
598  uint32_t bws_failed_next;
599  uint32_t bws_disk_nr;
601 };
602 
613  struct conf_pver_base_walk_st *st)
614 {
615  const struct m0_conf_objv *objv;
616  unsigned level;
617 
619  return M0_RC(M0_CW_CONTINUE);
620  objv = M0_CONF_CAST(obj, m0_conf_objv);
622  M0_LOG(M0_DEBUG, "objv="FID_F" ix=%d real="FID_F" level=%u",
623  FID_P(&obj->co_id), objv->cv_ix, FID_P(&objv->cv_real->co_id),
624  level);
625  if (st->bws_failed == NULL) {
626  if (objv->cv_real->co_ha_state != M0_NC_ONLINE) {
628  return M0_RC(M0_CW_SKIP_SUBTREE);
629  }
630  } else if (st->bws_failed_next < st->bws_failed->ai_count &&
631  objv->cv_ix == st->bws_failed->ai_elems[
632  st->bws_failed_next]) {
633  ++st->bws_failed_next;
634  if (st->bws_allowance[level] == 0)
635  return M0_ERR_INFO(-EINVAL, "Failures are not"
636  " compatible with allowance vector at"
637  " level %u", level);
638  --st->bws_allowance[level];
639  return M0_RC(M0_CW_SKIP_SUBTREE);
640  }
641  return M0_RC(0);
642 }
643 
645 static int conf_pver_base_w(struct m0_conf_obj *obj, void *args)
646 {
647  struct conf_pver_base_walk_st *st = args;
648  struct m0_conf_cache *cache = obj->co_cache;
649  unsigned level;
650  struct m0_fid virt_fid;
651  struct m0_conf_obj *new_obj;
652  struct m0_conf_objv *new_objv;
653  const struct m0_fid *downlink;
654  int rc;
655 
657  if (rc != 0)
658  return rc; /* don't use M0_ERR or M0_RC here */
660  virt_fid = conf_objv_virtual_fid(cache);
661  /*
662  * Create a stub of m0_conf_objv.
663  */
664  new_obj = m0_conf_obj_create(&virt_fid, cache);
665  new_objv = M0_CONF_CAST(new_obj, m0_conf_objv);
666  new_objv->cv_real = M0_CONF_CAST(obj, m0_conf_objv)->cv_real;
667  /* Add it to the parent directory. */
668  m0_conf_dir_add(st->bws_dirs[level], new_obj);
669 
670  rc = m0_conf_cache_add(cache, new_obj);
671  /* m0_conf_cache_add() cannot fail, because conf_objv_virtual_fid()
672  * returns unique fids. */
673  M0_ASSERT(rc == 0);
674 
675  downlink = new_obj->co_ops->coo_downlinks(new_obj)[0];
676  if (downlink == NULL) {
678  M0_CNT_INC(st->bws_disk_nr);
679  goto out;
680  }
681  /* Create new_objv->cv_children directory. */
682  rc = m0_conf_dir_new(new_obj, downlink, &M0_CONF_OBJV_TYPE, NULL,
683  &new_objv->cv_children);
684  M0_ASSERT_INFO(rc == 0, "XXX BUG: error handling is not implemented");
685  st->bws_dirs[level + 1] = new_objv->cv_children;
686 out:
687  new_obj->co_status = M0_CS_READY;
688  M0_POST(m0_conf_obj_invariant(new_obj));
689  return M0_CW_CONTINUE;
690 }
691 
697 {
698  int rc;
699  uint32_t level = 0;
700 
701  M0_PRE(pver->pv_kind == M0_CONF_PVER_VIRTUAL);
702 
703  do {
705  if (rc == -EINVAL)
706  M0_CNT_DEC(pver->pv_u.subtree.pvs_tolerance[level]);
707  } while (rc == -EINVAL);
708  return rc;
709 }
710 
725 static int conf_pver_virtual_create(const struct m0_fid *fid,
726  struct m0_conf_pver *base,
727  const uint32_t *allowance,
728  struct arr_int *failed,
729  struct m0_conf_pver **out)
730 {
731  struct m0_conf_obj *pvobj;
732  struct m0_conf_pver *pver;
733  struct m0_conf_pver_subtree *pvsub;
734  struct m0_conf_cache *cache = base->pv_obj.co_cache;
735  struct conf_pver_base_walk_st st;
736  int rc;
737 
738  { /* Validate the fid. */
739  enum m0_conf_pver_kind kind;
740  rc = m0_conf_pver_fid_read(fid, &kind, NULL, NULL);
741  M0_PRE(rc == 0 && kind == M0_CONF_PVER_VIRTUAL);
742  }
743  M0_PRE(base->pv_kind == M0_CONF_PVER_ACTUAL);
744  M0_PRE(ergo(failed == NULL,
746  base->pv_u.subtree.pvs_recd[i] ==
747  allowance[i])) &&
748  _0C(!M0_IS0(&base->pv_u.subtree.pvs_recd))));
749  M0_PRE(failed == NULL ||
750  failed->ai_count == m0_reduce(i, M0_CONF_PVER_HEIGHT, 0,
751  + allowance[i]));
752 
753  pvobj = m0_conf_obj_create(fid, cache);
754  if (pvobj == NULL)
755  return M0_ERR(-ENOMEM);
756 
757  pver = M0_CONF_CAST(pvobj, m0_conf_pver);
758  pver->pv_kind = M0_CONF_PVER_VIRTUAL;
759  pvsub = &pver->pv_u.subtree;
760  /* Copy attributes from base. */
761  pvsub->pvs_attr = base->pv_u.subtree.pvs_attr;
762  memcpy(pvsub->pvs_tolerance, base->pv_u.subtree.pvs_tolerance,
763  sizeof pvsub->pvs_tolerance);
764  rc = m0_conf_cache_add(cache, pvobj);
765  /* m0_conf_cache_add() cannot fail: conf_pver_virtual_create()
766  * would not be called if the object existed in the cache. */
767  M0_ASSERT(rc == 0);
768  rc = m0_conf_dir_new(pvobj, &M0_CONF_PVER_SITEVS_FID,
769  &M0_CONF_OBJV_TYPE, NULL, &pvsub->pvs_sitevs);
770  if (rc != 0) {
771  rc = M0_ERR(rc);
772  goto err;
773  }
774  pvobj->co_status = M0_CS_READY;
775 
776  /* Pre-walking state initialisation. */
777  memcpy(st.bws_allowance, allowance, sizeof st.bws_allowance);
778  st.bws_failed = failed;
779  st.bws_failed_next = 0;
780  st.bws_disk_nr = 0;
782  /* Build virtual pver subtree. */
783  rc = m0_conf_walk(conf_pver_base_w, &base->pv_obj, &st);
784  if (rc != 0) {
785  rc = M0_ERR(rc);
786  goto err;
787  }
788  pvsub->pvs_attr.pa_P = st.bws_disk_nr;
789  /* Validate the pver attributes */
790  if (!m0_pdclust_attr_check(&pvsub->pvs_attr)) {
791  rc = M0_ERR(-EINVAL);
792  goto err;
793  }
794  M0_ASSERT(pvsub->pvs_attr.pa_P > allowance[M0_CONF_PVER_LVL_DRIVES]);
796  if (rc != 0) {
797  rc = M0_ERR(rc);
798  goto err;
799  }
800  /* Post-walking state verification. */
802  M0_ASSERT(failed == NULL ||
804 
806  *out = pver;
807  return M0_RC(0);
808 err:
810  return rc;
811 }
812 
817  const uint32_t *srecd)
818 {
819  int i = 0;
820  int result = MAX_FAILURES_NOT_REACHED;
821  uint32_t tolerance ;
822 
823  while(i < M0_CONF_PVER_HEIGHT) {
824  tolerance = pv->pv_u.subtree.pvs_tolerance[i];
825  /* Ignore the case of srecd[i] == tolerance == 0. */
826  if (srecd[i] > 0 && srecd[i] == tolerance)
827  result = MAX_FAILURES_REACHED;
828  else if (srecd[i] > tolerance) {
829  result = MAX_FAILURES_EXCEEDED;
830  break;
831  }
832  i++;
833  }
834  return result;
835 }
836 
838  struct m0_confc *confc,
839  struct m0_conf_pver_info *out_info)
840 {
841  struct m0_conf_root *root;
842  struct m0_conf_pver *pver;
843  int rc;
844  int i = 0;
845  int failures_at_lvl;
846  uint32_t srecd[M0_CONF_PVER_HEIGHT];
847  uint32_t failures = 0;
848  uint32_t K;
849  uint32_t *tolerance;
850 
851  M0_ENTRY();
852  M0_PRE(fid != NULL);
853  M0_PRE(confc != NULL);
854 
857  if (rc != 0)
858  return M0_ERR(rc);
859  out_info->cpi_fid = *fid;
860  out_info->cpi_attr = pver->pv_u.subtree.pvs_attr;
861  K = pver->pv_u.subtree.pvs_attr.pa_K;
862 
863  M0_SET_ARR0(srecd);
865  rc = m0_conf_walk(conf_pver_recd_build, &pver->pv_obj, srecd);
867  if (rc != 0)
868  return M0_ERR(rc);
869 
870  while (i < M0_CONF_PVER_HEIGHT)
871  failures += srecd[i++];
872 
873  failures_at_lvl = tolerance_failure_cmp(pver, srecd);
874  tolerance = pver->pv_u.subtree.pvs_tolerance;
875 
885  if (failures == 0)
886  out_info->cpi_state = M0_CPS_HEALTHY;
887  if (failures > 0 && failures < K &&
888  failures_at_lvl == MAX_FAILURES_NOT_REACHED)
889  out_info->cpi_state = M0_CPS_DEGRADED;
890  if (failures == K || failures_at_lvl == MAX_FAILURES_REACHED)
891  out_info->cpi_state = M0_CPS_CRITICAL;
892  if (failures > K || failures_at_lvl == MAX_FAILURES_EXCEEDED)
893  out_info->cpi_state = M0_CPS_DAMAGED;
894 
895  M0_LOG(M0_DEBUG, "state: %d, failures: %d", out_info->cpi_state, failures);
896  CONF_PVER_VECTOR_LOG("failed objs of", FID_P(&pver->pv_obj.co_id), srecd);
897  CONF_PVER_VECTOR_LOG("tolerance of", FID_P(&pver->pv_obj.co_id), tolerance);
898 
899  return M0_RC(rc);
900 } M0_EXPORTED(m0_conf_pver_status);
901 
903 {
904  M0_PRE(!obj->co_deleted);
905  obj->co_deleted = true;
906  return M0_CW_CONTINUE;
907 }
908 
910 {
911  int rc;
912 
914 
916  M0_ASSERT(rc == 0); /* conf_obj_mark_deleted() cannot fail */
917  m0_conf_cache_gc(obj->co_cache);
918 }
919 
920 #undef CONF_PVER_VECTOR_LOG
921 
922 #undef M0_TRACE_SUBSYSTEM
923 
const struct m0_conf_obj_type * m0_conf_obj_type(const struct m0_conf_obj *obj)
Definition: obj.c:363
struct m0_fid co_id
Definition: obj.h:208
Definition: beck.c:235
struct m0_conf_obj * cc_root
Definition: confc.h:404
#define M0_PRE(cond)
#define M0_ALLOC_ARR(arr, nr)
Definition: memory.h:84
const struct m0_conf_obj_type M0_CONF_OBJV_TYPE
Definition: objv.c:151
#define m0_conf_glob_init(glob, flags, errfunc, cache, origin,...)
Definition: glob.h:142
uint32_t bws_allowance[M0_CONF_PVER_HEIGHT]
Definition: pvers.c:596
struct m0_conf_dir * pvs_sitevs
Definition: obj.h:478
M0_INTERNAL bool m0_conf_pver_is_clean(const struct m0_conf_pver *pver)
Definition: pvers.c:281
struct m0_pdclust_attr pvs_attr
Definition: obj.h:481
#define NULL
Definition: misc.h:38
#define ergo(a, b)
Definition: misc.h:293
uint32_t ai_count
Definition: pvers.c:57
const struct m0_conf_obj_type M0_CONF_SITE_TYPE
Definition: site.c:121
M0_INTERNAL int m0_fd_tolerance_check(struct m0_conf_pver *pv, uint32_t *failure_level)
Definition: fd.c:250
struct m0_conf_obj rt_obj
Definition: obj.h:372
M0_INTERNAL struct m0_conf_obj * m0_conf_cache_lookup(const struct m0_conf_cache *cache, const struct m0_fid *id)
Definition: cache.c:106
M0_INTERNAL void m0_conf_dir_add(struct m0_conf_dir *dir, struct m0_conf_obj *obj)
Definition: dir.c:43
struct m0_pool_version * pv
Definition: dir.c:629
#define M0_LOG(level,...)
Definition: trace.h:167
struct m0_container container
const struct m0_conf_obj_type * m0_conf_fid_type(const struct m0_fid *fid)
Definition: obj.c:368
enum m0_trace_level level
Definition: trace.c:111
const struct m0_conf_obj_type M0_CONF_PVER_TYPE
Definition: pver.c:260
uint8_t ft_id
Definition: fid.h:101
static int conf_pver_formulate(const struct m0_conf_pver *fpver, struct m0_conf_pver **out)
Definition: pvers.c:419
struct m0_conf_obj pv_obj
Definition: obj.h:533
#define CONF_PVER_VECTOR_LOG(owner, fid, vector)
Definition: pvers.c:41
static int conf_pver_failures_cid(struct m0_conf_pver *base, uint64_t *out)
Definition: pvers.c:559
M0_INTERNAL void m0_combination_inverse(int cid, int N, int K, int *x)
Definition: combinations.c:79
static int conf_pver_objvs_count(struct m0_conf_pver *base, uint32_t *out)
Definition: pvers.c:492
struct m0_conf_cache * co_cache
Definition: obj.h:251
Definition: ub.c:49
M0_INTERNAL unsigned m0_conf_pver_level(const struct m0_conf_obj *obj)
Definition: pvers.c:394
uint32_t pvf_allowance[M0_CONF_PVER_HEIGHT]
Definition: obj.h:512
struct m0_conf_dir * bws_dirs[M0_CONF_PVER_HEIGHT]
Definition: pvers.c:600
M0_INTERNAL bool m0_conf_obj_is_stub(const struct m0_conf_obj *obj)
Definition: obj.c:302
m0_conf_pver_kind
Definition: obj.h:516
static struct foo * obj
Definition: tlist.c:302
const struct m0_conf_obj_type M0_CONF_CONTROLLER_TYPE
Definition: controller.c:131
static int conf_pver_find_by_fid_locked(const struct m0_fid *fid, const struct m0_conf_root *root, struct m0_conf_pver **out)
Definition: pvers.c:160
enum m0_conf_pver_state cpi_state
Definition: pvers.h:132
enum m0_conf_pver_kind pv_kind
Definition: obj.h:535
#define m0_tl_endfor
Definition: tlist.h:700
struct m0_fid fid
Definition: di.c:46
const struct arr_int * bws_failed
Definition: pvers.c:597
return M0_RC(rc)
struct m0_pdclust_attr cpi_attr
Definition: pvers.h:129
struct m0_fid pvf_base
Definition: obj.h:501
#define M0_ENTRY(...)
Definition: trace.h:170
M0_INTERNAL int m0_conf_dir_new(struct m0_conf_obj *parent, const struct m0_fid *relfid, const struct m0_conf_obj_type *children_type, const struct m0_fid_arr *children_ids, struct m0_conf_dir **out)
Definition: dir.c:159
struct m0_tl cd_items
Definition: obj.h:360
int i
Definition: dir.c:1033
def args
Definition: addb2db.py:716
#define M0_SET_ARR0(arr)
Definition: misc.h:72
#define M0_ERR_INFO(rc, fmt,...)
Definition: trace.h:215
M0_INTERNAL int m0_conf_walk(int(*fn)(struct m0_conf_obj *obj, void *args), struct m0_conf_obj *origin, void *args)
Definition: walk.c:49
struct m0_conf_root * root
Definition: note.c:50
return M0_ERR(-EOPNOTSUPP)
Definition: trace.h:482
static int key
Definition: locality.c:283
M0_INTERNAL int m0_conf_pver_formulaic_find(uint32_t fpver_id, const struct m0_conf_root *root, const struct m0_conf_pver **out)
Definition: pvers.c:231
#define M0_FID_TINIT(type, container, key)
Definition: fid.h:90
const struct m0_conf_obj_type M0_CONF_ENCLOSURE_TYPE
Definition: enclosure.c:140
int cv_ix
Definition: obj.h:550
const struct m0_fid_type cot_ftype
Definition: obj.h:314
#define M0_ASSERT(cond)
static struct m0_confc * confc
Definition: file.c:94
M0_INTERNAL int m0_combination_index(int N, int K, int *x)
Definition: combinations.c:52
uint32_t ap_pos
Definition: pvers.c:63
const struct m0_fid **(* coo_downlinks)(const struct m0_conf_obj *obj)
Definition: obj_ops.h:151
static struct m0_fid conf_objv_virtual_fid(struct m0_conf_cache *cache)
Definition: pvers.c:377
struct m0_fid pver
Definition: idx_dix.c:74
union m0_conf_pver::@122 pv_u
enum m0_ha_obj_state co_ha_state
Definition: obj.h:241
static struct m0_thread t[8]
Definition: service_ut.c:1230
uint32_t pvs_tolerance[M0_CONF_PVER_HEIGHT]
Definition: obj.h:487
M0_INTERNAL struct m0_fid m0_conf_pver_fid(enum m0_conf_pver_kind kind, uint64_t container, uint64_t key)
Definition: pvers.c:309
Definition: pvers.c:56
struct m0_conf_cache cc_cache
Definition: confc.h:394
static int conf_pver_virtual_create(const struct m0_fid *fid, struct m0_conf_pver *base, const uint32_t *allowance, struct arr_int *failed, struct m0_conf_pver **out)
Definition: pvers.c:725
uint32_t pvf_id
Definition: obj.h:493
M0_INTERNAL bool m0_conf_cache_is_locked(const struct m0_conf_cache *cache)
Definition: cache.c:60
uint32_t bws_disk_nr
Definition: pvers.c:599
uint64_t f_container
Definition: fid.h:39
#define M0_POST(cond)
M0_INTERNAL int m0_conf_pver_fid_read(const struct m0_fid *fid, enum m0_conf_pver_kind *kind, uint64_t *container, uint64_t *key)
Definition: pvers.c:352
const struct m0_conf_obj_type M0_CONF_DRIVE_TYPE
Definition: drive.c:108
static int conf_pver_base_w(struct m0_conf_obj *obj, void *args)
Definition: pvers.c:645
static int conf_obj_mark_deleted(struct m0_conf_obj *obj, void *args M0_UNUSED)
Definition: pvers.c:902
#define M0_CONF_CAST(ptr, type)
Definition: obj.h:780
static int conf_pver_base_recd_update(const struct m0_conf_pool *pool)
Definition: pvers.c:108
M0_INTERNAL int m0_conf_cache_add(struct m0_conf_cache *cache, struct m0_conf_obj *obj)
Definition: cache.c:79
static int conf_objv_failed_fill(struct m0_conf_obj *obj, void *args)
Definition: pvers.c:537
#define FID_P(f)
Definition: fid.h:77
int m0_conf_pver_status(struct m0_fid *fid, struct m0_confc *confc, struct m0_conf_pver_info *out_info)
Definition: pvers.c:837
struct m0_fid cpi_fid
Definition: pvers.h:126
struct arr_int ap_arr
Definition: pvers.c:62
static struct m0_pool pool
Definition: iter_ut.c:58
M0_INTERNAL bool m0_fid_eq(const struct m0_fid *fid0, const struct m0_fid *fid1)
Definition: fid.c:164
#define m0_forall(var, nr,...)
Definition: misc.h:112
static int conf_pver_find_locked(const struct m0_conf_pool *pool, const struct m0_fid *pver_to_skip, struct m0_conf_pver **out)
Definition: pvers.c:126
M0_INTERNAL struct m0_conf_obj * m0_conf_obj_create(const struct m0_fid *id, struct m0_conf_cache *cache)
Definition: obj_ops.c:80
#define M0_CNT_INC(cnt)
Definition: arith.h:226
Definition: fid.h:38
uint64_t f_key
Definition: fid.h:40
M0_INTERNAL int m0_conf_pver_find_by_fid(const struct m0_fid *fid, const struct m0_conf_root *root, struct m0_conf_pver **out)
Definition: pvers.c:219
#define M0_IS0(obj)
Definition: misc.h:70
int * ai_elems
Definition: pvers.c:58
uint32_t pa_P
Definition: pdclust.h:115
struct m0_conf_pver_formulaic formulaic
Definition: obj.h:538
static void conf_pver_subtree_delete(struct m0_conf_obj *obj)
Definition: pvers.c:909
#define _0C(exp)
Definition: assert.h:311
static int conf_pver_recd_build(struct m0_conf_obj *obj, void *args)
Definition: pvers.c:519
enum m0_conf_status co_status
Definition: obj.h:210
static int conf_pver_base_obj_check(struct m0_conf_obj *obj, struct conf_pver_base_walk_st *st)
Definition: pvers.c:612
struct m0_conf_dir * cv_children
Definition: obj.h:545
#define M0_CNT_DEC(cnt)
Definition: arith.h:219
M0_INTERNAL int m0_conf_glob(struct m0_conf_glob *glob, uint32_t nr, const struct m0_conf_obj **objv)
Definition: glob.c:92
#define M0_ASSERT_INFO(cond, fmt,...)
static int conf_pver_formulaic_base(const struct m0_conf_pver *fpver, struct m0_conf_pver **out)
Definition: pvers.c:262
M0_INTERNAL void m0_conf_cache_gc(struct m0_conf_cache *cache)
Definition: cache.c:176
static uint64_t base
Definition: dump.c:1504
static void conf_pver_enumerate(struct m0_conf_pver *pver)
Definition: pvers.c:481
static int tolerance_failure_cmp(struct m0_conf_pver *pv, const uint32_t *srecd)
Definition: pvers.c:816
#define out(...)
Definition: gen.c:41
M0_INTERNAL int m0_conf_pver_find(const struct m0_conf_pool *pool, const struct m0_fid *pver_to_skip, struct m0_conf_pver **out)
Definition: pvers.c:207
M0_INTERNAL void m0_conf_cache_lock(struct m0_conf_cache *cache)
Definition: cache.c:50
#define m0_tl_for(name, head, obj)
Definition: tlist.h:695
void m0_free(void *data)
Definition: memory.c:146
static int conf_pver_formulaic_find_locked(uint32_t fpver_id, const struct m0_conf_root *root, const struct m0_conf_pver **out)
Definition: pvers.c:80
M0_INTERNAL int m0_conf_pver_formulaic_from_virtual(const struct m0_conf_pver *virtual, const struct m0_conf_root *root, const struct m0_conf_pver **out)
Definition: pvers.c:244
int32_t rc
Definition: trigger_fop.h:47
#define ARRAY_SIZE(a)
Definition: misc.h:45
M0_INTERNAL void m0_conf_cache_unlock(struct m0_conf_cache *cache)
Definition: cache.c:55
M0_INTERNAL bool m0_conf_obj_invariant(const struct m0_conf_obj *obj)
Definition: obj_ops.c:52
const struct m0_conf_obj_type M0_CONF_RACK_TYPE
Definition: rack.c:124
struct m0_conf_obj * cv_real
Definition: obj.h:558
#define FID_F
Definition: fid.h:75
uint32_t bws_failed_next
Definition: pvers.c:598
static int conf_pver_tolerance_adjust(struct m0_conf_pver *pver)
Definition: pvers.c:696
Definition: idx_mock.c:47
const struct m0_conf_obj_ops * co_ops
Definition: obj.h:212
#define M0_IMPOSSIBLE(fmt,...)
static int conf_pver_enumerate_w(struct m0_conf_obj *obj, void *args)
Definition: pvers.c:450
#define M0_UNUSED
Definition: misc.h:380
M0_INTERNAL bool m0_pdclust_attr_check(const struct m0_pdclust_attr *attr)
Definition: pdclust.c:340