Motr  M0
confc.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2015-2020 Seagate Technology LLC and/or its Affiliates
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * For any questions about this software or licensing,
18  * please email opensource@seagate.com or cortx-questions@seagate.com.
19  *
20  */
21 
22 
23 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_CONF
24 #include "lib/trace.h"
25 
26 #include "conf/confc.h"
27 #include "conf/cache.h"
28 #include "conf/obj_ops.h" /* m0_conf_obj_find */
29 #include "conf/preload.h" /* m0_confstr_parse */
30 #include "conf/fop.h" /* m0_conf_fetch_fopt */
31 #include "motr/magic.h" /* M0_CONFC_MAGIC, M0_CONFC_CTX_MAGIC */
32 #include "fop/fom_generic.h" /* m0_rpc_item_is_generic_reply_fop */
33 #include "rpc/rpc.h" /* m0_rpc_post */
34 #include "fid/fid.h" /* m0_fid_is_set */
35 #include "rpc/rpclib.h" /* m0_rpc_client_connect */
36 #include "rpc/rpc_machine.h" /* m0_rpc_machine_lock */
37 #include "lib/arith.h" /* M0_CNT_INC, M0_CNT_DEC */
38 #include "lib/misc.h" /* M0_IN */
39 #include "lib/errno.h" /* ENOMEM, EPROTO */
40 #include "lib/memory.h" /* M0_ALLOC_ARR, m0_free */
41 #include "lib/finject.h"
42 
281 
290 /* ------------------------------------------------------------------
291  * State definitions
292  * ------------------------------------------------------------------ */
293 
294 static int check_st_in(struct m0_sm *mach); /* S_CHECK */
295 static int wait_reply_st_in(struct m0_sm *mach); /* S_WAIT_REPLY */
296 static int skip_confd_st_in(struct m0_sm *mach); /* S_SKIP_CONFD */
297 static int retry_confd_st_in(struct m0_sm *mach); /* S_RETRY_CONFD */
298 static int grow_cache_st_in(struct m0_sm *mach); /* S_GROW_CACHE */
299 static int failure_st_in(struct m0_sm *mach); /* S_FAILURE */
300 
301 static bool check_st_invariant(const struct m0_sm *mach); /* S_CHECK */
302 static bool failure_st_invariant(const struct m0_sm *mach); /* S_FAILURE */
303 static bool terminal_st_invariant(const struct m0_sm *mach); /* S_TERMINAL */
304 
307  S_INITIAL, /* 0 */
308  S_CHECK, /* 1 */
309  S_WAIT_REPLY, /* 2 */
310  S_WAIT_STATUS, /* 3 */
311  S_RETRY_CONFD, /* 4 */
312  S_SKIP_CONFD, /* 5 */
313  S_GROW_CACHE, /* 6 */
314  S_FAILURE, /* 7 */
315  S_TERMINAL, /* 8 */
317 };
318 
320  [S_INITIAL] = {
322  .sd_name = "S_INITIAL",
323  .sd_in = NULL,
324  .sd_ex = NULL,
325  .sd_invariant = NULL,
326  .sd_allowed = M0_BITS(S_CHECK, S_FAILURE)
327  },
328  [S_CHECK] = {
329  .sd_flags = 0,
330  .sd_name = "S_CHECK",
331  .sd_in = check_st_in,
332  .sd_ex = NULL,
333  .sd_invariant = check_st_invariant,
335  S_FAILURE)
336  },
337  [S_WAIT_REPLY] = {
338  .sd_flags = M0_SDF_FINAL,
339  .sd_name = "S_WAIT_REPLY",
340  .sd_in = wait_reply_st_in,
341  .sd_ex = NULL,
342  .sd_invariant = NULL,
344  S_SKIP_CONFD)
345  },
346  [S_WAIT_STATUS] = {
347  .sd_flags = 0,
348  .sd_name = "S_WAIT_STATUS",
349  .sd_in = NULL,
350  .sd_ex = NULL,
351  .sd_invariant = NULL,
352  .sd_allowed = M0_BITS(S_CHECK)
353  },
354  [S_RETRY_CONFD] = {
355  .sd_flags = 0,
356  .sd_name = "S_RETRY_CONFD",
357  .sd_in = retry_confd_st_in,
358  .sd_ex = NULL,
359  .sd_invariant = NULL,
360  .sd_allowed = M0_BITS(S_CHECK)
361  },
362  [S_SKIP_CONFD] = {
363  .sd_flags = 0,
364  .sd_name = "S_SKIP_CONFD",
365  .sd_in = skip_confd_st_in,
366  .sd_ex = NULL,
367  .sd_invariant = NULL,
368  .sd_allowed = M0_BITS(S_CHECK, S_FAILURE)
369  },
370  [S_GROW_CACHE] = {
371  .sd_flags = 0,
372  .sd_name = "S_GROW_CACHE",
373  .sd_in = grow_cache_st_in,
374  .sd_ex = NULL,
375  .sd_invariant = NULL,
376  .sd_allowed = M0_BITS(S_CHECK, S_FAILURE)
377  },
378  [S_FAILURE] = {
379  .sd_flags = M0_SDF_FAILURE | M0_SDF_FINAL,
380  .sd_name = "S_FAILURE",
381  .sd_in = failure_st_in,
382  .sd_ex = NULL,
383  .sd_invariant = failure_st_invariant,
384  .sd_allowed = 0
385  },
386  [S_TERMINAL] = {
387  .sd_flags = M0_SDF_TERMINAL,
388  .sd_name = "S_TERMINAL",
389  .sd_in = NULL,
390  .sd_ex = NULL,
391  .sd_invariant = terminal_st_invariant,
392  .sd_allowed = 0
393  }
394 };
395 
396 static const struct m0_sm_conf confc_ctx_states_conf = {
397  .scf_name = "states of m0_confc_ctx::fc_mach",
398  .scf_nr_states = S_NR,
399  .scf_state = confc_ctx_states
400 };
401 
402 /* ------------------------------------------------------------------
403  * Bob types and invariants
404  * ------------------------------------------------------------------ */
405 
406 static bool _confc_check(const void *bob);
407 static bool _ctx_check(const void *bob);
408 
409 static const struct m0_bob_type confc_bob = {
410  .bt_name = "m0_confc",
411  .bt_magix_offset = M0_MAGIX_OFFSET(struct m0_confc, cc_magic),
412  .bt_magix = M0_CONFC_MAGIC,
413  .bt_check = _confc_check
414 };
415 M0_BOB_DEFINE(static, &confc_bob, m0_confc);
416 
417 static const struct m0_bob_type ctx_bob = {
418  .bt_name = "m0_confc_ctx",
419  .bt_magix_offset = M0_MAGIX_OFFSET(struct m0_confc_ctx, fc_magic),
420  .bt_magix = M0_CONFC_CTX_MAGIC,
421  .bt_check = _ctx_check
422 };
424 
425 M0_INTERNAL bool m0_confc_invariant(const struct m0_confc *confc)
426 {
427  return m0_confc_bob_check(confc);
428 }
429 
430 static bool ctx_invariant(const struct m0_confc_ctx *ctx)
431 {
432  M0_PRE(ctx != NULL);
433  return m0_confc_ctx_bob_check(ctx);
434 }
435 
436 /* ------------------------------------------------------------------
437  * m0_confc
438  * ------------------------------------------------------------------ */
439 static int confc_cache_preload(struct m0_confc *confc, const char *local_conf);
440 static int connect_to_confd(struct m0_confc *confc, const char *confd_addr,
441  struct m0_rpc_machine *rpc_mach);
442 static void disconnect_from_confd(struct m0_confc *confc);
443 static void confc_lock(struct m0_confc *confc);
444 static void confc_unlock(struct m0_confc *confc);
445 static bool confc_is_locked(const struct m0_confc *confc);
446 static void clink_cleanup_fini(struct m0_clink *link);
447 
448 M0_INTERNAL bool m0_confc_is_inited(const struct m0_confc *confc)
449 {
450  return confc->cc_group != NULL;
451 }
452 
453 M0_INTERNAL bool m0_confc_is_online(const struct m0_confc *confc)
454 {
456 }
457 
458 static bool not_empty(const char *s)
459 {
460  return s != NULL && *s != '\0';
461 }
462 
463 static int confc_cache_create(struct m0_confc *confc,
464  const char *local_conf)
465 {
466  int rc;
467 
468  M0_ENTRY("confc=%p", confc);
470 
472 
473  /* Create stub for root object */
475  &confc->cc_root);
476  if (rc != 0)
477  return M0_ERR(rc);
478 
479  if (not_empty(local_conf))
481  return M0_RC(rc);
482 }
483 
484 M0_INTERNAL int m0_confc_reconnect(struct m0_confc *confc,
485  struct m0_rpc_machine *rpc_mach,
486  const char *confd_addr)
487 {
488  int rc;
489 
490  M0_ENTRY("confc = %p, confd_addr = %s", confc, confd_addr);
491  confc_lock(confc);
495  if (confd_addr == NULL)
496  /*
497  * Just want to disconnect confc in rconfc_conductor_drained()
498  * Don't return the error because log messages confuse.
499  */
500  rc = 0;
501  else if (*confd_addr == '\0')
502  rc = M0_ERR(-EINVAL);
503  else
504  rc = connect_to_confd(confc, confd_addr, rpc_mach);
505  M0_POST(ergo(rc == 0,
509  return M0_RC(rc);
510 }
511 
512 M0_INTERNAL int m0_confc_init_wait(struct m0_confc *confc,
513  struct m0_sm_group *sm_group,
514  const char *confd_addr,
515  struct m0_rpc_machine *rpc_mach,
516  const char *local_conf,
517  uint64_t timeout_ns)
518 {
519  int rc;
520 
521  M0_ENTRY("confc=%p", confc);
522  M0_PRE(sm_group != NULL);
523  M0_PRE(ergo(not_empty(confd_addr), rpc_mach != NULL));
524  M0_LOG(M0_DEBUG, "confd=%s lconf=%s", confd_addr, local_conf);
525 
527  confc_lock(confc);
530  if (rc != 0)
531  goto err;
532 
533  confc->cc_rpc_timeout = timeout_ns;
536  if (not_empty(confd_addr))
537  rc = connect_to_confd(confc, confd_addr, rpc_mach);
538 
539  if (rc == 0) {
540  confc->cc_group = sm_group;
541  confc->cc_nr_ctx = 0;
542  m0_confc_bob_init(confc);
545  confc->cc_gops = NULL;
547 
550  return M0_RC(0);
551  }
552 err:
553  confc->cc_root = NULL;
556 
557  return M0_ERR_INFO(rc, "confc=%p confd_addr=%s", confc, confd_addr);
558 }
559 
560 M0_INTERNAL int m0_confc_init(struct m0_confc *confc,
561  struct m0_sm_group *sm_group,
562  const char *confd_addr,
563  struct m0_rpc_machine *rpc_mach,
564  const char *local_conf)
565 {
566  return m0_confc_init_wait(confc, sm_group, confd_addr, rpc_mach,
568 }
569 
570 M0_INTERNAL void m0_confc_fini(struct m0_confc *confc)
571 {
572  M0_ENTRY("confc=%p", confc);
573  M0_PRE(confc->cc_nr_ctx == 0);
574 
578  confc->cc_gops = NULL;
579  m0_confc_bob_fini(confc); /* performs _confc_check() */
580 
583 
584  confc->cc_group = NULL;
585  confc->cc_root = NULL;
588 
589  M0_LEAVE();
590 }
591 
592 M0_INTERNAL struct m0_confc *m0_confc_from_obj(const struct m0_conf_obj *obj)
593 {
594  return bob_of(obj->co_cache, struct m0_confc, cc_cache, &confc_bob);
595 }
596 
597 M0_INTERNAL void m0_confc_gate_ops_set(struct m0_confc *confc,
598  struct m0_confc_gate_ops *gops)
599 {
600  M0_PRE(confc != NULL);
601  M0_PRE(gops == NULL || gops->go_check != NULL);
603  confc->cc_gops = gops;
604  if (gops != NULL && gops->go_drain != NULL) {
607  }
608 }
609 
610 static bool _confc_check(const void *bob)
611 {
612  const struct m0_confc *confc = bob;
613  return
614  _0C(confc->cc_group != NULL) &&
615  _0C(confc->cc_root == NULL ||
617 }
618 
619 static void clink_cleanup_fini(struct m0_clink *link)
620 {
621  if (link->cl_chan != NULL) {
623  if (m0_clink_is_armed(link)) {
624  m0_clink_del(link);
625  m0_clink_fini(link);
626  M0_SET0(link);
627  }
628  }
629 }
630 
631 /* ------------------------------------------------------------------
632  * m0_confc_ctx
633  * ------------------------------------------------------------------ */
634 
635 static bool on_object_updated(struct m0_clink *link);
636 static bool request_check(const struct m0_confc_ctx *ctx);
637 static bool eop(const struct m0_fid *buf);
638 static void confc_group_lock(const struct m0_confc *confc);
639 static void confc_group_unlock(const struct m0_confc *confc);
640 static bool confc_group_is_locked(const struct m0_confc *confc);
641 
642 M0_INTERNAL int
644 {
645  bool ok;
646 
647  M0_ENTRY("ctx=%p", ctx);
649 
650  confc_lock(confc);
651  ok = confc->cc_gops == NULL ||
657  if (ok) {
658  M0_LOG(M0_DEBUG, "ctx=%p confc=%p nr_ctx: %"PRIu32" -> %"PRIu32,
660  M0_CNT_INC(confc->cc_nr_ctx); /* attach to m0_confc */
661  }
663  if (!ok)
664  return M0_ERR_INFO(-EPERM, "Conf reading is not allowed"
665  " [ctx=%p]", ctx);
666 
667  *ctx = (struct m0_confc_ctx){ .fc_confc = confc };
669  confc->cc_group);
670  ctx->fc_ast.sa_datum = ctx;
671  m0_clink_init(&ctx->fc_clink, on_object_updated);
672  m0_confc_ctx_bob_init(ctx);
673  ctx->fc_finalized = false;
674 
676  M0_LEAVE("ctx=%p", ctx);
677  return 0;
678 }
679 
680 M0_INTERNAL void m0_confc_ctx_fini_locked(struct m0_confc_ctx *ctx)
681 {
682  struct m0_confc *confc = ctx->fc_confc;
683 
684  M0_ENTRY("ctx=%p", ctx);
687 
688  ctx->fc_finalized = true;
689  m0_clink_fini(&ctx->fc_clink);
690  ctx->fc_origin = NULL;
691 
692  confc_lock(confc);
693  if (ctx->fc_result != NULL) {
694  M0_ASSERT(ctx->fc_mach.sm_state == S_TERMINAL);
695  m0_conf_obj_put(ctx->fc_result);
696  }
697  M0_LOG(M0_DEBUG, "ctx=%p confc=%p nr_ctx: %"PRIu32" -> %"PRIu32,
699  M0_CNT_DEC(confc->cc_nr_ctx); /* detach from m0_confc */
700  if (confc->cc_nr_ctx == 0)
703 
704  m0_sm_fini(&ctx->fc_mach);
705 
706  if (ctx->fc_rpc_item != NULL) {
707  m0_rpc_item_put_lock(ctx->fc_rpc_item);
708  ctx->fc_rpc_item = NULL;
709  }
710 
711  m0_confc_ctx_bob_fini(ctx);
712  ctx->fc_confc = NULL;
713  M0_LEAVE("ctx=%p", ctx);
714 }
715 
716 M0_INTERNAL void m0_confc_ctx_fini(struct m0_confc_ctx *ctx)
717 {
718  struct m0_confc *confc = ctx->fc_confc;
719 
720  M0_ENTRY();
721  confc_group_lock(confc); /* needed for m0_sm_fini() */
724  M0_LEAVE();
725 }
726 
727 static bool _ctx_check(const void *bob)
728 {
729  const struct m0_confc_ctx *ctx = bob;
730  const struct m0_sm *mach = &ctx->fc_mach;
731 
732  return _0C(m0_confc_invariant(ctx->fc_confc)) &&
733  _0C(ctx->fc_ast.sa_datum == ctx) &&
734  _0C(ctx->fc_clink.cl_cb == on_object_updated) &&
735  _0C(ergo(ctx->fc_rpc_item != NULL, request_check(ctx))) &&
736  _0C(ergo(mach->sm_state == S_TERMINAL, mach->sm_rc == 0)) &&
737  _0C(ergo(mach->sm_state == S_FAILURE, mach->sm_rc < 0)) &&
738  _0C(ergo(ctx->fc_origin != NULL,
739  m0_conf_obj_invariant(ctx->fc_origin)));
740 }
741 
742 M0_INTERNAL bool m0_confc_ctx_is_completed(const struct m0_confc_ctx *ctx)
743 {
744  M0_PRE(confc_group_is_locked(ctx->fc_confc));
746  return M0_IN(ctx->fc_mach.sm_state, (S_TERMINAL, S_FAILURE));
747 }
748 
749 M0_INTERNAL bool m0_confc_ctx_is_completed_lock(const struct m0_confc_ctx *ctx)
750 {
751  bool res;
752 
753  confc_group_lock(ctx->fc_confc);
755  confc_group_unlock(ctx->fc_confc);
756  return res;
757 }
758 
759 M0_INTERNAL int32_t m0_confc_ctx_error(const struct m0_confc_ctx *ctx)
760 {
762  return ctx->fc_mach.sm_rc;
763 }
764 
765 M0_INTERNAL int32_t m0_confc_ctx_error_lock(const struct m0_confc_ctx *ctx)
766 {
768  return ctx->fc_mach.sm_rc;
769 }
770 
771 M0_INTERNAL struct m0_conf_obj *m0_confc_ctx_result(struct m0_confc_ctx *ctx)
772 {
773  struct m0_conf_obj *res = ctx->fc_result;
774 
775  M0_ENTRY("ctx=%p", ctx);
777  M0_PRE(ctx->fc_mach.sm_state == S_TERMINAL);
779 
780  ctx->fc_result = NULL;
781 
782  M0_LEAVE("retval=%p", res);
783  return res;
784 }
785 
786 /* ----------------------------------------------------------------
787  * sm_waiter
788  * ---------------------------------------------------------------- */
789 
790 struct sm_waiter {
793 };
794 
796 static bool sm__filter(struct m0_clink *link)
797 {
798  return !m0_confc_ctx_is_completed(&container_of(link, struct sm_waiter,
799  w_clink)->w_ctx);
800 }
801 
802 static int sm_waiter_init(struct sm_waiter *w, struct m0_confc *confc)
803 {
804  int rc = m0_confc_ctx_init(&w->w_ctx, confc);
805  if (rc == 0) {
807  M0_LOG(M0_DEBUG, "adding clink %p to chan %p",
808  &w->w_clink, &w->w_ctx.fc_mach.sm_chan);
810  }
811  return M0_RC(rc);
812 }
813 
814 static void sm_waiter_fini(struct sm_waiter *w)
815 {
817  m0_clink_fini(&w->w_clink);
819 }
820 
821 static int sm_waiter_wait(struct sm_waiter *w, struct m0_conf_obj **result)
822 {
823  int rc;
824 
825  M0_ENTRY();
826 
827  /*
828  * The context may be changed by AST callback, and it is possible that
829  * the one is not in invariant state when checking for completion. To
830  * prevent this, we need to ensure that the confc is locked.
831  */
833  m0_chan_wait(&w->w_clink);
835  if (rc == 0)
836  *result = m0_confc_ctx_result(&w->w_ctx);
837 
838  return M0_RC(rc);
839 }
840 
841 /* ------------------------------------------------------------------
842  * open/close
843  * ------------------------------------------------------------------ */
844 
845 static void ctx_state_set (struct m0_confc_ctx *ctx, enum confc_ctx_state state);
846 static void ctx_state_fail(struct m0_confc_ctx *ctx, int rc);
847 static int path_copy(const struct m0_fid *src, struct m0_fid *dest,
848  size_t dest_sz);
849 
850 M0_INTERNAL void m0_confc__open(struct m0_confc_ctx *ctx,
851  struct m0_conf_obj *origin,
852  const struct m0_fid *path)
853 {
854  int rc = 0;
855 
856  M0_ENTRY("ctx=%p origin=%p", ctx, origin);
857  M0_PRE(ctx_invariant(ctx) && ctx->fc_mach.sm_state == S_INITIAL);
858  M0_PRE(ctx->fc_origin == NULL && eop(ctx->fc_path));
859 
860  if (origin == NULL) {
861  ctx->fc_origin = ctx->fc_confc->cc_root;
862  } else if (M0_FI_ENABLED("invalid-origin") ||
863  unlikely(origin->co_cache != &ctx->fc_confc->cc_cache)) {
864  /*
865  * `origin' may be freed at this point.
866  *
867  * Possible scenario (MOTR-2363):
868  *
869  * -- Let confc->cc_root = A.
870  * m0_confc_root_open
871  * \_ m0_confc_open_sync (origin=A)
872  * \_ m0_confc__open_sync
873  * \_ sm_waiter_init
874  * | \_ m0_confc_ctx_init
875  * | \_ rconfc_gate_check -- blocks until
876  * | -- conf cache is ready
877  * ------------------------------------------------------------
878  * -- Another thread calls _confc_cache_clean(). The function
879  * -- frees all conf objects - including 'A'! - and changes
880  * -- the value of confc->cc_root pointer.
881  * ------------------------------------------------------------
882  * \_ m0_confc__open (origin=A)
883  * -- Since `A' has already been freed, origin->co_cache will
884  * -- contain invalid data.
885  */
886  rc = M0_ERR_INFO(-EAGAIN, "Invalid origin: %p", origin);
887  } else {
888  M0_PRE(m0_conf_obj_invariant(origin));
889  ctx->fc_origin = origin;
890  }
891  rc = rc ?: path_copy(path, ctx->fc_path, ARRAY_SIZE(ctx->fc_path));
892  if (rc == 0)
894  else
896  M0_LEAVE();
897 }
898 
899 M0_INTERNAL int m0_confc__open_sync(struct m0_conf_obj **result,
900  struct m0_conf_obj *origin,
901  const struct m0_fid *path)
902 {
903  struct sm_waiter w;
904  int rc;
905 
906  M0_ENTRY();
907  M0_PRE(origin != NULL);
908  M0_PRE(m0_conf_obj_invariant(origin));
909 
910  rc = sm_waiter_init(&w, m0_confc_from_obj(origin));
911  if (rc != 0)
912  return M0_ERR(rc);
913  m0_confc__open(&w.w_ctx, origin, path);
914  rc = sm_waiter_wait(&w, result);
915  sm_waiter_fini(&w);
916 
917  M0_POST(ergo(rc == 0, (*result)->co_status == M0_CS_READY));
918  return M0_RC(rc);
919 }
920 
921 M0_INTERNAL void m0_confc_close(struct m0_conf_obj *obj)
922 {
923  if (obj != NULL) {
927  }
928 }
929 
930 M0_INTERNAL void m0_confc_open_by_fid(struct m0_confc_ctx *ctx,
931  const struct m0_fid *fid)
932 {
933  struct m0_conf_obj *obj;
934  int rc;
935 
936  rc = m0_conf_obj_find_lock(&ctx->fc_confc->cc_cache, fid, &obj);
937  if (rc == 0)
939  else
941 }
942 
943 M0_INTERNAL int m0_confc_open_by_fid_sync(struct m0_confc *confc,
944  const struct m0_fid *fid,
945  struct m0_conf_obj **result)
946 {
947  struct sm_waiter w;
948  int rc;
949 
950  M0_ENTRY();
951 
952  rc = sm_waiter_init(&w, confc);
953  if (rc != 0)
954  return M0_ERR(rc);
956  rc = sm_waiter_wait(&w, result);
957  sm_waiter_fini(&w);
958 
959  M0_POST(ergo(rc == 0, (*result)->co_status == M0_CS_READY));
960  return M0_RC(rc);
961 }
962 
969 static int
970 path_copy(const struct m0_fid *src, struct m0_fid *dest, size_t dest_sz)
971 {
972  size_t i;
973 
974  M0_ENTRY();
975 
976  for (i = 0; i < dest_sz && !eop(&src[i]); ++i)
977  dest[i] = src[i];
978 
979  if (i == dest_sz)
980  return M0_ERR(-E2BIG);
981  dest[i] = (struct m0_fid)M0_FID0; /* terminate the path */
982 
983  return M0_RC(0);
984 }
985 
986 /* ------------------------------------------------------------------
987  * readdir
988  * ------------------------------------------------------------------ */
989 
990 M0_INTERNAL int m0_confc_readdir(struct m0_confc_ctx *ctx,
991  struct m0_conf_obj *dir,
992  struct m0_conf_obj **pptr)
993 {
994  int rc;
995 
996  M0_ENTRY("ctx=%p dir=%p *pptr=%p", ctx, dir, *pptr);
998  dir->co_cache == &ctx->fc_confc->cc_cache);
999 
1001  rc = dir->co_ops->coo_readdir(dir, pptr);
1002  if (rc == M0_CONF_DIRMISS) {
1003  /*
1004  * Request {origin, [relation, entry]} from confd, where
1005  * origin is dir's parent,
1006  * relation is how dir is referred to by the origin,
1007  * entry is the first missing entry in the dir.
1008  */
1009  struct m0_fid path[] = {
1010  M0_CONF_CAST(dir, m0_conf_dir)->cd_relfid,
1011  (*pptr)->co_id,
1012  M0_FID0
1013  };
1014  m0_confc__open(ctx, dir->co_parent, path);
1015  }
1017  return M0_RC(rc);
1018 }
1019 
1020 M0_INTERNAL int m0_confc_readdir_sync(struct m0_conf_obj *dir,
1021  struct m0_conf_obj **pptr)
1022 {
1023  struct sm_waiter w;
1024  int rc;
1025 
1026  M0_ENTRY("dir=%p *pptr=%p", dir, *pptr);
1027 
1029  if (rc != 0)
1030  return M0_ERR(rc);
1031  rc = m0_confc_readdir(&w.w_ctx, dir, pptr);
1032  if (rc == M0_CONF_DIRMISS)
1033  rc = sm_waiter_wait(&w, pptr) ?:
1034  (*pptr == NULL ? M0_CONF_DIREND : M0_CONF_DIRNEXT);
1035  else
1037  sm_waiter_fini(&w);
1038  return M0_RC(rc);
1039 }
1040 
1041 /* ------------------------------------------------------------------
1042  * Casts
1043  * ------------------------------------------------------------------ */
1044 
1045 M0_INTERNAL struct m0_rpc_conn *m0_confc2conn(struct m0_confc *confc)
1046 {
1047  return &confc->cc_rlink.rlk_conn;
1048 }
1049 
1050 M0_INTERNAL struct m0_rpc_session *m0_confc2sess(struct m0_confc *confc)
1051 {
1052  return &confc->cc_rlink.rlk_sess;
1053 }
1054 
1055 static struct m0_confc_ctx *mach_to_ctx(struct m0_sm *mach)
1056 {
1057  return bob_of(mach, struct m0_confc_ctx, fc_mach, &ctx_bob);
1058 }
1059 
1060 static const struct m0_confc_ctx *const_mach_to_ctx(const struct m0_sm *mach)
1061 {
1062  return bob_of(mach, const struct m0_confc_ctx, fc_mach, &ctx_bob);
1063 }
1064 
1065 static struct m0_confc_ctx *ast_to_ctx(struct m0_sm_ast *ast)
1066 {
1067  return bob_of(ast, struct m0_confc_ctx, fc_ast, &ctx_bob);
1068 }
1069 
1070 /* ------------------------------------------------------------------
1071  * State transitions
1072  *
1073  * Note, that *_st_in() functions don't need to assert that the group
1074  * lock is being hold. This check is part of state machine invariant
1075  * (m0_sm_invariant()), which is asserted when a state is entered (and
1076  * left).
1077  * ------------------------------------------------------------------ */
1078 
1079 static int path_walk(struct m0_confc_ctx *ctx);
1080 static int cache_grow(struct m0_confc *confc,
1081  const struct m0_conf_fetch_resp *resp);
1082 static struct m0_confc_ctx *item_to_ctx(const struct m0_rpc_item *item);
1083 static uint64_t *confc_cache_ver(struct m0_confc_ctx *ctx);
1084 
1086 static int check_st_in(struct m0_sm *mach)
1087 {
1088  static const int next_state[] = {
1092  };
1093  int rc;
1094  struct m0_confc_ctx *ctx = mach_to_ctx(mach);
1095 
1096  M0_ENTRY("mach=%p ctx=%p", mach, ctx);
1097 
1098  rc = path_walk(ctx);
1099  if (rc < 0) {
1100  mach->sm_rc = rc;
1101  M0_LEAVE("retval=S_FAILURE rc=%d", rc);
1102  return S_FAILURE;
1103  }
1104 
1105  M0_ASSERT(IS_IN_ARRAY(rc, next_state));
1106  M0_LEAVE("retval=%d", next_state[rc]);
1107  return next_state[rc];
1108 }
1109 
1111 static int wait_reply_st_in(struct m0_sm *mach)
1112 {
1113  struct m0_confc_ctx *ctx = mach_to_ctx(mach);
1114  int rc;
1115 
1116  M0_ENTRY("mach=%p ctx=%p", mach, ctx);
1117  M0_PRE(ctx->fc_rpc_item != NULL);
1118 
1119  rc = m0_rpc_post(ctx->fc_rpc_item);
1120  if (rc == 0)
1121  return M0_RC(-1);
1122  mach->sm_rc = rc;
1123  M0_LEAVE("retval=S_FAILURE rc=%d", rc);
1124  return S_FAILURE;
1125 }
1126 
1132 {
1133  struct m0_rpc_item *item = ctx->fc_rpc_item;
1134  struct m0_confc *confc = ctx->fc_confc;
1135  struct m0_conf_obj *obj;
1136  struct m0_conf_fetch *req;
1137 
1139  confc_lock(confc);
1140  obj = m0_conf_cache_lookup(&confc->cc_cache, &req->f_origin);
1142  M0_ASSERT(obj->co_status == M0_CS_LOADING);
1143  obj->co_status = M0_CS_MISSING;
1144 }
1145 
1147 static int retry_confd_st_in(struct m0_sm *mach)
1148 {
1149  struct m0_confc_ctx *ctx = mach_to_ctx(mach);
1150 
1151  M0_ENTRY("mach=%p ctx=%p", mach, ctx);
1152 
1154  /* end up with rpc item which is not needed anymore */
1155  m0_rpc_item_put_lock(ctx->fc_rpc_item);
1156  ctx->fc_rpc_item = NULL;
1157 
1158  /*
1159  * Retry with the last missing object
1160  */
1161  M0_LEAVE("retval=S_CHECK");
1162  return S_CHECK;
1163 }
1164 
1166 static int skip_confd_st_in(struct m0_sm *mach)
1167 {
1168  struct m0_confc_ctx *ctx = mach_to_ctx(mach);
1169  int rc;
1170 
1171  M0_ENTRY("mach=%p ctx=%p", mach, ctx);
1172  M0_PRE(ctx->fc_confc->cc_gops != NULL &&
1173  ctx->fc_confc->cc_gops->go_skip != NULL);
1174 
1175  /* ask rconfc to skip current confd and connect confc to other one */
1176  rc = ctx->fc_confc->cc_gops->go_skip(ctx->fc_confc);
1177  if (M0_FI_ENABLED("force_reconnect_success"))
1178  rc = 0;
1179  if (rc == 0)
1181  /* end up with rpc item which is not needed anymore */
1182  m0_rpc_item_put_lock(ctx->fc_rpc_item);
1183  ctx->fc_rpc_item = NULL;
1184 
1185  mach->sm_rc = rc;
1186  M0_LEAVE("rc=%d retval=%s", rc, rc == 0 ? "S_CHECK" : "S_FAILURE");
1187  return rc == 0 ? S_CHECK : S_FAILURE;
1188 }
1189 
1191 static int grow_cache_st_in(struct m0_sm *mach)
1192 {
1193  struct m0_conf_fetch_resp *resp;
1194  int rc;
1195  struct m0_confc_ctx *ctx = mach_to_ctx(mach);
1196  struct m0_rpc_item *item = ctx->fc_rpc_item;
1197  struct m0_rpc_machine *rmach = item->ri_rmachine;
1198 
1199  M0_ENTRY("mach=%p ctx=%p", mach, ctx);
1200  M0_PRE(item != NULL && item->ri_error == 0 && item->ri_reply != NULL &&
1201  rmach != NULL);
1202 
1204  rc = resp->fr_rc;
1206  /* the very first fetch occurred */
1207  *confc_cache_ver(ctx) = resp->fr_ver;
1208  else if (*confc_cache_ver(ctx) != resp->fr_ver)
1209  rc = M0_ERR(-EPROTO);
1210 
1211  if (rc == 0)
1212  rc = cache_grow(ctx->fc_confc, resp);
1213 
1214  m0_rpc_machine_lock(rmach);
1215  /* Let the rpc layer free memory allocated for response. */
1217  /* The item has been consumed and is not needed any more. */
1219  m0_rpc_machine_unlock(rmach);
1220  ctx->fc_rpc_item = NULL;
1221 
1222  mach->sm_rc = rc;
1223  M0_LEAVE("rc=%d retval=%s", rc, rc == 0 ? "S_CHECK" : "S_FAILURE");
1224  return rc == 0 ? S_CHECK : S_FAILURE;
1225 }
1226 
1228 static int failure_st_in(struct m0_sm *mach)
1229 {
1230  struct m0_confc_ctx *ctx = mach_to_ctx(mach);
1231  M0_ENTRY("mach=%p ctx=%p", mach, ctx);
1232 
1233  /*
1234  * Unset M0_CS_LOADING object with path_walk() in order for
1235  * m0_confc_fini() not to fail:
1236  * m0_confc_fini
1237  * \_ m0_conf_cache_fini
1238  * \_ _obj_del
1239  * \_ m0_conf_obj_delete
1240  * \_ M0_PRE(obj->co_status != M0_CS_LOADING)
1241  *
1242  * ctx->fc_origin may be NULL; see "Invalid origin" in m0_confc__open().
1243  */
1244  if (likely(ctx->fc_origin != NULL))
1245  (void)path_walk(ctx);
1246 
1247  return M0_RC(-1);
1248 }
1249 
1251 static void on_replied(struct m0_rpc_item *item)
1252 {
1253  struct m0_confc_ctx *ctx = item_to_ctx(item);
1254  int rc;
1255 
1256  M0_ENTRY("item=%p ctx=%p", item, ctx);
1258 
1260  if (M0_FI_ENABLED("fail_rpc_reply"))
1261  rc = M0_ERR(-EPERM);
1262  if (rc == 0) {
1265  } else {
1266  /*
1267  * See if the confc is a 'conductor' governed by rconfc. In case
1268  * it is, try to switch to other confd running the same version.
1269  */
1270  if (ctx->fc_confc->cc_gops != NULL &&
1271  ctx->fc_confc->cc_gops->go_skip != NULL)
1273  else if (rc == -EAGAIN)
1275  else
1276  ctx_state_fail(ctx, rc);
1277  }
1278  M0_LEAVE("rc=%d", rc);
1279 }
1280 
1282 static bool on_object_updated(struct m0_clink *link)
1283 {
1284  struct m0_confc_ctx *ctx = bob_of(link->cl_group, struct m0_confc_ctx,
1285  fc_clink, &ctx_bob);
1286 
1287  M0_ENTRY();
1288  M0_PRE(confc_is_locked(ctx->fc_confc));
1289 
1290  m0_clink_del(&ctx->fc_clink);
1292 
1293  M0_LEAVE();
1294  return true; /* event is consumed */
1295 }
1296 
1297 static bool check_st_invariant(const struct m0_sm *mach)
1298 {
1299  const struct m0_confc_ctx *ctx = const_mach_to_ctx(mach);
1300  return mach->sm_rc == 0 && ctx->fc_result == NULL &&
1301  ctx_invariant(ctx);
1302 }
1303 
1304 static bool failure_st_invariant(const struct m0_sm *mach)
1305 {
1306  const struct m0_confc_ctx *ctx = const_mach_to_ctx(mach);
1307  return ctx->fc_result == NULL && ctx->fc_mach.sm_rc < 0;
1308 }
1309 
1310 static bool terminal_st_invariant(const struct m0_sm *mach)
1311 {
1312  /* We do not check m0_confc_ctx::fc_result, because it may
1313  * have been unset by m0_confc_ctx_result(). */
1314  return mach->sm_rc == 0;
1315 }
1316 
1317 static uint64_t *confc_cache_ver(struct m0_confc_ctx *ctx)
1318 {
1319  return &ctx->fc_confc->cc_cache.ca_ver;
1320 }
1321 
1322 /* ------------------------------------------------------------------
1323  * Walkies
1324  *
1325  * They're "Techno Trousers". Ex-NASA. Fantastic for walkies!
1326  * ------------------------------------------------------------------ */
1327 
1328 static int path_walk_complete(struct m0_confc_ctx *ctx, struct m0_conf_obj *obj,
1329  size_t ri);
1330 static int request_create(struct m0_confc_ctx *ctx,
1331  const struct m0_conf_obj *orig, size_t ri);
1332 static bool confc_group_is_locked(const struct m0_confc *confc);
1333 
1335 static bool eop(const struct m0_fid *id)
1336 {
1337  return !m0_fid_is_set(id);
1338 }
1339 
1365 static int path_walk(struct m0_confc_ctx *ctx)
1366 {
1367  struct m0_conf_obj *obj;
1368  size_t ri;
1369  int rc;
1370 
1371  M0_ENTRY("ctx=%p", ctx);
1372  M0_PRE(confc_group_is_locked(ctx->fc_confc));
1373  M0_PRE(m0_conf_obj_invariant(ctx->fc_origin));
1374  M0_PRE(M0_IN(ctx->fc_mach.sm_state, (S_CHECK, S_FAILURE)));
1375 
1376  confc_lock(ctx->fc_confc);
1377 
1378  for (rc = 0, obj = ctx->fc_origin, ri = 0;
1379  rc == 0 && obj->co_status == M0_CS_READY &&
1380  !eop(&ctx->fc_path[ri]);
1381  ++ri)
1382  rc = obj->co_ops->coo_lookup(obj, &ctx->fc_path[ri], &obj);
1383 
1384  if (rc == 0)
1385  rc = path_walk_complete(ctx, obj, ri);
1386  else
1387  M0_ASSERT(rc == -ENOENT);
1388 
1389  confc_unlock(ctx->fc_confc);
1390 
1391  M0_POST(confc_group_is_locked(ctx->fc_confc));
1392  return M0_RC(rc);
1393 }
1394 
1405 static int
1406 path_walk_complete(struct m0_confc_ctx *ctx, struct m0_conf_obj *obj, size_t ri)
1407 {
1408  int rc;
1409 
1410  M0_ENTRY("ctx=%p obj=%p ri=%zu", ctx, obj, ri);
1411  M0_PRE(confc_group_is_locked(ctx->fc_confc));
1412  M0_PRE(confc_is_locked(ctx->fc_confc));
1413 
1414  switch (obj->co_status) {
1415  case M0_CS_READY:
1416  M0_ASSERT(eop(&ctx->fc_path[ri]));
1417 
1419  ctx->fc_result = obj;
1420 
1421  M0_POST(m0_conf_obj_invariant(ctx->fc_result));
1422  M0_LEAVE("retval=M0_CS_READY");
1423  return M0_CS_READY;
1424 
1425  case M0_CS_MISSING:
1426  obj->co_status = M0_CS_LOADING;
1428  /*
1429  * Directory objects don't travel over the
1430  * network. Query the parent object.
1431  */
1432  M0_ASSERT(obj->co_parent != NULL);
1433  obj = obj->co_parent;
1434  M0_CNT_DEC(ri);
1435  }
1436  /* In multi confd setup, main confd may restart and
1437  * other confd will takeover, so until then retry the
1438  * request.
1439  */
1440  if (m0_confc_is_online(ctx->fc_confc)) {
1441  rc = request_create(ctx, obj, ri);
1442  if (rc == 0) {
1443  M0_LEAVE("retval=M0_CS_MISSING");
1444  return M0_CS_MISSING;
1445  }
1446  } else
1447  rc = M0_ERR(-EAGAIN);
1448 
1449  return M0_RC(rc);
1450 
1451  case M0_CS_LOADING:
1452  if (ctx->fc_mach.sm_state == S_FAILURE) {
1453  obj->co_status = M0_CS_MISSING;
1454  m0_chan_broadcast(&obj->co_chan);
1455  break;
1456  }
1457  m0_clink_add(&obj->co_chan, &ctx->fc_clink);
1458  M0_LEAVE("retval=M0_CS_LOADING");
1459  return M0_CS_LOADING;
1460 
1461  default:
1462  M0_IMPOSSIBLE("Invalid object status");
1463  }
1464  return M0_RC(-1);
1465 }
1466 
1467 /* ------------------------------------------------------------------
1468  * AST
1469  * ------------------------------------------------------------------ */
1470 
1471 static void _state_set(struct m0_sm_group *grp M0_UNUSED, struct m0_sm_ast *ast)
1472 {
1473  struct m0_confc_ctx *ctx = ast->sa_datum;
1474  int state;
1475 
1476  if (ctx->fc_confc == NULL) {
1477  /* the 'ctx' is already finalized */
1478  return;
1479  }
1480 
1481  M0_ASSERT(ast_to_ctx(ast) == ctx);
1482 
1483  state = ctx->fc_ast_datum;
1486  /* note the absence of S_FAILURE */
1487  S_TERMINAL)));
1488 
1489  m0_sm_state_set(&ctx->fc_mach, state);
1490 }
1491 
1492 static void
1494 {
1495  struct m0_confc_ctx *ctx = ast->sa_datum;
1496  int rc;
1497 
1498  if (ctx->fc_confc == NULL || ctx->fc_finalized) {
1499  /* the 'ctx' is already finalized */
1500  M0_LOG(M0_DEBUG, "ctx %p is already finalized", ctx);
1501  return;
1502  }
1503 
1504  M0_ASSERT(ast_to_ctx(ast) == ctx);
1505  if (m0_confc_ctx_is_completed(ctx) || ctx->fc_mach.sm_rc < 0) {
1506  /*
1507  * Because this can be called from multiple sources,
1508  * we just return if the failure state is already set
1509  * from other sources or it is already completed.
1510  */
1511  M0_LOG(M0_DEBUG, "ctx %p is already failed/completed", ctx);
1512  return;
1513  }
1514 
1515  rc = ctx->fc_ast_datum;
1516  m0_sm_fail(&ctx->fc_mach, S_FAILURE, rc);
1517 }
1518 
1519 static void _ast_post(struct m0_sm_ast *ast,
1520  void (*cb)(struct m0_sm_group *, struct m0_sm_ast *),
1521  int datum)
1522 {
1523  struct m0_confc_ctx *ctx = ast_to_ctx(ast);
1524 
1525  ast->sa_cb = cb;
1526  M0_ASSERT(ast->sa_datum == ctx);
1527  ctx->fc_ast_datum = datum;
1528 
1529  m0_sm_ast_post(ctx->fc_confc->cc_group, ast);
1530 }
1531 
1533 static void ctx_state_set(struct m0_confc_ctx *ctx, enum confc_ctx_state state)
1534 {
1535  struct m0_sm_ast *ast = &ctx->fc_ast;
1536  _ast_post(ast, _state_set, state);
1537 }
1538 
1540 static void ctx_state_fail(struct m0_confc_ctx *ctx, int rc)
1541 {
1542  struct m0_sm_ast *ast = &ctx->fc_ast;
1544 }
1545 
1546 /* ------------------------------------------------------------------
1547  * Configuration cache management
1548  * ------------------------------------------------------------------ */
1549 
1550 static int object_enrich(struct m0_conf_obj *dest,
1551  const struct m0_confx_obj *src,
1552  struct m0_confc *confc)
1553 {
1554  int rc;
1555 
1556  M0_ENTRY();
1559  M0_PRE(dest->co_cache == &confc->cc_cache);
1560 
1561  if (!m0_conf_obj_match(dest, src))
1562  return M0_ERR_INFO(-EPROTO, "Conflict of incoming and cached "
1563  "configuration data: src="FID_F" dest="FID_F,
1564  FID_P(&src->xo_u.u_header.ch_id),
1565  FID_P(&dest->co_id));
1566  if (dest->co_status == M0_CS_READY)
1567  return M0_RC(0); /* do nothing */
1568 
1570  M0_ASSERT(dest->co_status == (rc == 0 ? M0_CS_READY : M0_CS_MISSING));
1571  m0_chan_broadcast(&dest->co_chan);
1572 
1573  return M0_RC(rc);
1574 }
1575 
1576 static int
1577 cached_obj_update(struct m0_confc *confc, const struct m0_confx_obj *flat)
1578 {
1579  struct m0_conf_obj *obj;
1580 
1581  M0_ENTRY("confc=%p", confc);
1583  &obj) ?: object_enrich(obj, flat, confc));
1584 }
1585 
1587 static int confc_cache_preload(struct m0_confc *confc, const char *local_conf)
1588 {
1589  struct m0_confx *enc;
1590  uint32_t i;
1591  int rc;
1592 
1593  M0_ENTRY();
1595 
1596  rc = m0_confstr_parse(local_conf, &enc);
1597  if (rc == 0) {
1598  for (i = 0; i < enc->cx_nr && rc == 0; ++i)
1600  m0_confx_free(enc);
1601  }
1602  return M0_RC(rc);
1603 }
1604 
1611 static int
1612 cache_grow(struct m0_confc *confc, const struct m0_conf_fetch_resp *resp)
1613 {
1614  struct m0_confx_obj *flat;
1615  uint32_t i;
1616  int rc = 0;
1617 
1618  M0_ENTRY();
1619  M0_PRE(resp->fr_rc == 0);
1621 
1622  confc_lock(confc);
1623  for (i = 0; i < resp->fr_data.cx_nr; ++i) {
1624  flat = M0_CONFX_AT(&resp->fr_data, i);
1625 
1626  if (!m0_conf_fid_is_valid(m0_conf_objx_fid(flat))) {
1627  M0_LOG(M0_ERROR, "Invalid m0_confx_obj received");
1628  rc = -EPROTO;
1629  break;
1630  }
1631 
1632  rc = cached_obj_update(confc, flat);
1633  if (rc != 0)
1634  break;
1635  }
1637  return M0_RC(rc);
1638 }
1639 
1640 /* ------------------------------------------------------------------
1641  * Networking
1642  * ------------------------------------------------------------------ */
1643 
1644 static inline m0_time_t confc_deadline(const struct m0_confc *confc)
1645 {
1648 }
1649 
1650 static int connect_to_confd(struct m0_confc *confc, const char *confd_addr,
1651  struct m0_rpc_machine *rpc_mach)
1652 {
1653  enum { MAX_RPCS_IN_FLIGHT = 2 };
1654  int rc;
1655 
1656  M0_ENTRY();
1657  M0_PRE(not_empty(confd_addr) && rpc_mach != NULL);
1658  /*
1659  * The service fid passed to function below is NULL and hence the
1660  * link fom won't try to subscribe for ha callback on configuration
1661  * object for service, thus not needing a conf cache lock either.
1662  * This is needed because the caller of this function could be
1663  * holding a conf cache lock at this point.
1664  */
1665  rc = m0_rpc_link_init(&confc->cc_rlink, rpc_mach, NULL, confd_addr,
1667  if (rc != 0)
1668  return M0_ERR(rc);
1669 
1671  if (rc != 0)
1673 
1674  M0_POST((rc == 0) == confc->cc_rlink.rlk_connected);
1675  M0_POST(rc != 0 || m0_confc_is_online(confc));
1676  return M0_RC(rc);
1677 }
1678 
1680 {
1681  M0_ENTRY();
1684 
1688  M0_LEAVE();
1689 }
1690 
1709 struct confc_fop {
1710  /*
1711  * m0_fop must be the first member of confc_fop, so that
1712  * m0_fop_release() frees the whole confc_fop object.
1713  */
1714  struct m0_fop cf_fop;
1716 };
1717 
1718 static struct m0_confc_ctx *item_to_ctx(const struct m0_rpc_item *item)
1719 {
1720  M0_PRE(item != NULL);
1721  /* XXX TODO use bob_of() */
1723  cf_fop)->cf_ctx;
1724 }
1725 
1726 static void confc_fop_release(struct m0_ref *ref)
1727 {
1728  M0_ENTRY();
1729  M0_PRE(ref != NULL);
1730 
1731  /*
1732  * The memory, pointed to by ->f_path.ab_elems of
1733  * m0_conf_fetch, has never been allocated by xcode.
1734  * Nevertheless, m0_xcode_free() will try to free this memory,
1735  * because `m0_bufs' structure is recognized by xcode's
1736  * allocp() as one of the cases requiring dynamic memory
1737  * allocation.
1738  *
1739  * We zero m0_conf_fetch object so that m0_xcode_free() does
1740  * not segfault.
1741  */
1742  M0_SET0((struct m0_conf_fetch *)m0_fop_data(
1743  container_of(ref, struct m0_fop, f_ref)));
1744 
1745  m0_fop_release(ref);
1746 
1747  M0_LEAVE();
1748 }
1749 
1751 {
1752  struct confc_fop *p;
1753  int rc;
1754 
1755  M0_ALLOC_PTR(p);
1756  if (p == NULL)
1757  return NULL;
1758 
1760  rc = m0_fop_data_alloc(&p->cf_fop);
1761  if (rc != 0) {
1762  m0_free(p);
1763  return NULL;
1764  }
1765 
1766  p->cf_ctx = ctx;
1767  return p;
1768 }
1769 
1770 static const struct m0_rpc_item_ops confc_item_ops = {
1772 };
1773 
1787 static int request_create(struct m0_confc_ctx *ctx,
1788  const struct m0_conf_obj *orig, size_t ri)
1789 {
1790  struct confc_fop *p;
1791  struct m0_rpc_item *item;
1792  struct m0_conf_fetch *req;
1793  uint32_t len;
1794 
1795  M0_ENTRY("ctx=%p orig=%p ri=%zu", ctx, orig, ri);
1796  M0_PRE(ctx_invariant(ctx) && m0_confc_is_online(ctx->fc_confc) &&
1797  ctx->fc_rpc_item == NULL);
1798 
1799  p = confc_fop_alloc(ctx);
1800  if (p == NULL)
1801  return M0_ERR(-ENOMEM);
1802 
1803  /* Setup rpc item. */
1804  item = &p->cf_fop.f_item;
1806  item->ri_session = m0_confc2sess(ctx->fc_confc);
1807 
1808  /* Setup payload. */
1809  req = m0_fop_data(&p->cf_fop);
1810  req->f_origin = orig->co_id;
1811 
1812  for (len = 0; !eop(&ctx->fc_path[ri + len]); ++len)
1813  ; /* measure path length */
1814  req->f_path.af_count = len;
1815  req->f_path.af_elems = len == 0 ? NULL : &ctx->fc_path[ri];
1816 
1817  ctx->fc_rpc_item = item;
1818 
1820  return M0_RC(0);
1821 }
1822 
1823 static bool request_check(const struct m0_confc_ctx *ctx)
1824 {
1825  const struct m0_conf_fetch *req;
1826  const struct m0_rpc_item *item = ctx->fc_rpc_item;
1827 
1828  M0_PRE(item != NULL && m0_confc_is_online(ctx->fc_confc));
1829 
1831 
1832  return m0_conf_fid_is_valid(&req->f_origin) &&
1833  m0_fid_is_set(&req->f_origin) &&
1834  equi(req->f_path.af_count == 0, req->f_path.af_elems == NULL) &&
1836  item->ri_ops != NULL &&
1838  item->ri_session == m0_confc2sess(ctx->fc_confc) &&
1839  item_to_ctx(item) == ctx;
1840 }
1841 
1842 /* ------------------------------------------------------------------
1843  * Locking
1844  * ------------------------------------------------------------------ */
1845 
1846 static void confc_group_lock(const struct m0_confc *confc)
1847 {
1849 }
1850 
1851 static void confc_group_unlock(const struct m0_confc *confc)
1852 {
1854 }
1855 
1856 static bool confc_group_is_locked(const struct m0_confc *confc)
1857 {
1859 }
1860 
1861 static void confc_lock(struct m0_confc *confc)
1862 {
1864 }
1865 
1866 static void confc_unlock(struct m0_confc *confc)
1867 {
1869 }
1870 
1871 static bool confc_is_locked(const struct m0_confc *confc)
1872 {
1873  return m0_mutex_is_locked(&confc->cc_lock);
1874 }
1875 
1877 #undef M0_TRACE_SUBSYSTEM
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
M0_INTERNAL int m0_rpc_post(struct m0_rpc_item *item)
Definition: rpc.c:63
struct m0_sm_group * cc_group
Definition: confc.h:376
static struct m0_addb2_philter p
Definition: consumer.c:40
M0_INTERNAL void m0_chan_wait(struct m0_clink *link)
Definition: chan.c:336
#define unlikely(x)
Definition: assert.h:74
struct m0_conf_obj * cc_root
Definition: confc.h:404
#define M0_PRE(cond)
static bool check_st_invariant(const struct m0_sm *mach)
Definition: confc.c:1297
M0_INTERNAL void m0_sm_fail(struct m0_sm *mach, int fail_state, int32_t rc)
Definition: sm.c:468
M0_INTERNAL void m0_confx_free(struct m0_confx *enc)
Definition: preload.c:33
M0_INTERNAL void m0_mutex_unlock(struct m0_mutex *mutex)
Definition: mutex.c:66
const struct m0_conf_obj_type * m0_conf_objx_type(const struct m0_confx_obj *obj)
Definition: obj_ops.c:271
struct m0_clink cc_drain
Definition: confc.h:433
M0_INTERNAL bool m0_conf_obj_match(const struct m0_conf_obj *cached, const struct m0_confx_obj *flat)
Definition: obj_ops.c:254
M0_INTERNAL bool m0_chan_is_locked(const struct m0_chan *ch)
Definition: chan.c:78
static int path_walk(struct m0_confc_ctx *ctx)
Definition: confc.c:1365
#define NULL
Definition: misc.h:38
static int path_copy(const struct m0_fid *src, struct m0_fid *dest, size_t dest_sz)
Definition: confc.c:970
M0_INTERNAL void m0_clink_init(struct m0_clink *link, m0_chan_cb_t cb)
Definition: chan.c:201
M0_INTERNAL void m0_clink_del(struct m0_clink *link)
Definition: chan.c:267
M0_INTERNAL void m0_clink_del_lock(struct m0_clink *link)
Definition: chan.c:293
static void _state_fail(struct m0_sm_group *grp M0_UNUSED, struct m0_sm_ast *ast)
Definition: confc.c:1493
#define ergo(a, b)
Definition: misc.h:293
void(* sa_cb)(struct m0_sm_group *grp, struct m0_sm_ast *)
Definition: sm.h:506
M0_INTERNAL struct m0_conf_obj * m0_confc_ctx_result(struct m0_confc_ctx *ctx)
Definition: confc.c:771
Definition: sm.h:350
const m0_time_t M0_TIME_NEVER
Definition: time.c:108
static bool _ctx_check(const void *bob)
Definition: confc.c:727
static struct io_request req
Definition: file.c:100
static int request_create(struct m0_confc_ctx *ctx, const struct m0_conf_obj *orig, size_t ri)
Definition: confc.c:1787
M0_INTERNAL struct m0_rpc_conn * m0_confc2conn(struct m0_confc *confc)
Definition: confc.c:1045
static struct m0_sm_group * grp
Definition: bytecount.c:38
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_fop_init(struct m0_fop *fop, struct m0_fop_type *fopt, void *data, void(*fop_release)(struct m0_ref *))
Definition: fop.c:79
void m0_rpc_item_put(struct m0_rpc_item *item)
Definition: item.c:443
uint64_t m0_time_t
Definition: time.h:37
#define M0_LOG(level,...)
Definition: trace.h:167
M0_LEAVE()
static const struct m0_confc_ctx * const_mach_to_ctx(const struct m0_sm *mach)
Definition: confc.c:1060
struct m0_sm fc_mach
Definition: confc.h:538
M0_INTERNAL void m0_sm_ast_post(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: sm.c:135
bool(* go_check)(struct m0_confc *confc)
Definition: confc.h:462
void m0_rpc_item_get(struct m0_rpc_item *item)
Definition: item.c:434
static int confc_cache_preload(struct m0_confc *confc, const char *local_conf)
Definition: confc.c:1587
M0_INTERNAL int m0_confc_init(struct m0_confc *confc, struct m0_sm_group *sm_group, const char *confd_addr, struct m0_rpc_machine *rpc_mach, const char *local_conf)
Definition: confc.c:560
struct m0_fop cf_fop
Definition: confc.c:1714
static bool _confc_check(const void *bob)
Definition: confc.c:610
M0_INTERNAL void m0_conf_obj_put(struct m0_conf_obj *obj)
Definition: obj_ops.c:205
static bool confc_group_is_locked(const struct m0_confc *confc)
Definition: confc.c:1856
static int failure_st_in(struct m0_sm *mach)
Definition: confc.c:1228
static m0_time_t confc_deadline(const struct m0_confc *confc)
Definition: confc.c:1644
int32_t ri_error
Definition: item.h:161
void * m0_fop_data(const struct m0_fop *fop)
Definition: fop.c:220
M0_INTERNAL void m0_confc_fini(struct m0_confc *confc)
Definition: confc.c:570
M0_INTERNAL int32_t m0_confc_ctx_error_lock(const struct m0_confc_ctx *ctx)
Definition: confc.c:765
M0_INTERNAL bool m0_clink_is_armed(const struct m0_clink *link)
Definition: chan.c:303
static struct m0_addb2_mach * mach
Definition: storage.c:42
#define M0_BITS(...)
Definition: misc.h:236
static const struct m0_sm_conf confc_ctx_states_conf
Definition: confc.c:396
Definition: sm.h:504
#define M0_CONFX_AT(cx, idx)
Definition: onwire.h:271
struct m0_conf_cache * co_cache
Definition: obj.h:251
#define container_of(ptr, type, member)
Definition: misc.h:33
M0_INTERNAL void m0_confc_open_by_fid(struct m0_confc_ctx *ctx, const struct m0_fid *fid)
Definition: confc.c:930
#define M0_SET0(obj)
Definition: misc.h:64
M0_INTERNAL void m0_mutex_lock(struct m0_mutex *mutex)
Definition: mutex.c:49
static int confc_cache_create(struct m0_confc *confc, const char *local_conf)
Definition: confc.c:463
M0_INTERNAL bool m0_fid_is_set(const struct m0_fid *fid)
Definition: fid.c:106
uint64_t cc_rpc_timeout
Definition: confc.h:436
static struct m0_rpc_item * item
Definition: item.c:56
static void ctx_state_fail(struct m0_confc_ctx *ctx, int rc)
Definition: confc.c:1540
M0_INTERNAL int m0_confc_reconnect(struct m0_confc *confc, struct m0_rpc_machine *rpc_mach, const char *confd_addr)
Definition: confc.c:484
static struct foo * obj
Definition: tlist.c:302
const char * bt_name
Definition: bob.h:73
Definition: sock.c:887
static int retry_confd_st_in(struct m0_sm *mach)
Definition: confc.c:1147
static const struct m0_rpc_item_ops confc_item_ops
Definition: confc.c:1770
#define m0_confc_open(ctx, origin,...)
Definition: confc.h:678
struct m0_fid fid
Definition: di.c:46
return M0_RC(rc)
#define equi(a, b)
Definition: misc.h:297
M0_INTERNAL int m0_conf_obj_fill(struct m0_conf_obj *dest, const struct m0_confx_obj *src)
Definition: obj_ops.c:232
#define M0_ENTRY(...)
Definition: trace.h:170
static struct m0_sm_ast ast[NR]
Definition: locality.c:44
static void clink_cleanup_fini(struct m0_clink *link)
Definition: confc.c:619
int i
Definition: dir.c:1033
M0_INTERNAL void m0_conf_obj_get(struct m0_conf_obj *obj)
Definition: obj_ops.c:186
struct m0_rpc_machine * c_rpc_machine
Definition: conn.h:278
struct m0_confc_gate_ops * cc_gops
Definition: confc.h:426
static int wait_reply_st_in(struct m0_sm *mach)
Definition: confc.c:1111
#define M0_ERR_INFO(rc, fmt,...)
Definition: trace.h:215
return M0_ERR(-EOPNOTSUPP)
struct m0_confc_ctx w_ctx
Definition: confc.c:791
void * sa_datum
Definition: sm.h:508
M0_INTERNAL void m0_rpc_machine_unlock(struct m0_rpc_machine *machine)
Definition: rpc_machine.c:558
static void confc_group_unlock(const struct m0_confc *confc)
Definition: confc.c:1851
Definition: refs.h:34
uint32_t cx_nr
Definition: onwire.h:259
static int cache_grow(struct m0_confc *confc, const struct m0_conf_fetch_resp *resp)
Definition: confc.c:1612
M0_INTERNAL void m0_confc_ctx_fini(struct m0_confc_ctx *ctx)
Definition: confc.c:716
M0_INTERNAL void m0_chan_init(struct m0_chan *chan, struct m0_mutex *ch_guard)
Definition: chan.c:96
#define M0_ASSERT(cond)
const char * scf_name
Definition: sm.h:352
M0_INTERNAL void m0_confc_ctx_fini_locked(struct m0_confc_ctx *ctx)
Definition: confc.c:680
static struct m0_confc * confc
Definition: file.c:94
M0_INTERNAL bool m0_mutex_is_locked(const struct m0_mutex *mutex)
Definition: mutex.c:95
static struct m0_confc_ctx * item_to_ctx(const struct m0_rpc_item *item)
Definition: confc.c:1718
void m0_sm_state_set(struct m0_sm *mach, int state)
Definition: sm.c:478
M0_INTERNAL bool m0_confc_ctx_is_completed(const struct m0_confc_ctx *ctx)
Definition: confc.c:742
#define bob_of(ptr, type, field, bt)
Definition: bob.h:140
struct m0_confx fr_data
Definition: onwire.h:301
M0_INTERNAL void m0_conf_cache_init(struct m0_conf_cache *cache, struct m0_mutex *lock)
Definition: cache.c:66
bool(* go_drain)(struct m0_clink *clink)
Definition: confc.h:481
static char local_conf[]
Definition: file.c:115
M0_INTERNAL bool m0_confc_is_online(const struct m0_confc *confc)
Definition: confc.c:453
M0_INTERNAL int m0_confc_ctx_init(struct m0_confc_ctx *ctx, struct m0_confc *confc)
Definition: confc.c:643
static int connect_to_confd(struct m0_confc *confc, const char *confd_addr, struct m0_rpc_machine *rpc_mach)
Definition: confc.c:1650
struct m0_conf_cache cc_cache
Definition: confc.h:394
const char * confd_addr[]
confc_ctx_state
Definition: confc.c:306
static void _state_set(struct m0_sm_group *grp M0_UNUSED, struct m0_sm_ast *ast)
Definition: confc.c:1471
static bool not_empty(const char *s)
Definition: confc.c:458
static int object_enrich(struct m0_conf_obj *dest, const struct m0_confx_obj *src, struct m0_confc *confc)
Definition: confc.c:1550
struct m0_sm_ast fc_ast
Definition: confc.h:544
const struct m0_rpc_item_type * ri_type
Definition: item.h:200
M0_INTERNAL bool m0_confc_ctx_is_completed_lock(const struct m0_confc_ctx *ctx)
Definition: confc.c:749
struct m0_rpc_item * ri_reply
Definition: item.h:163
static void confc_group_lock(const struct m0_confc *confc)
Definition: confc.c:1846
static bool ctx_invariant(const struct m0_confc_ctx *ctx)
Definition: confc.c:430
M0_INTERNAL void m0_mutex_init(struct m0_mutex *mutex)
Definition: mutex.c:35
static bool sm__filter(struct m0_clink *link)
Definition: confc.c:796
static int grow_cache_st_in(struct m0_sm *mach)
Definition: confc.c:1191
M0_INTERNAL int m0_conf_obj_find_lock(struct m0_conf_cache *cache, const struct m0_fid *id, struct m0_conf_obj **out)
Definition: obj_ops.c:154
#define M0_POST(cond)
static bool request_check(const struct m0_confc_ctx *ctx)
Definition: confc.c:1823
M0_INTERNAL int m0_conf_obj_find(struct m0_conf_cache *cache, const struct m0_fid *id, struct m0_conf_obj **out)
Definition: obj_ops.c:136
struct m0_confc_ctx * cf_ctx
Definition: confc.c:1715
M0_INTERNAL int m0_fop_data_alloc(struct m0_fop *fop)
Definition: fop.c:71
M0_INTERNAL int m0_confc__open_sync(struct m0_conf_obj **result, struct m0_conf_obj *origin, const struct m0_fid *path)
Definition: confc.c:899
#define M0_CONF_CAST(ptr, type)
Definition: obj.h:780
M0_INTERNAL bool m0_confc_is_inited(const struct m0_confc *confc)
Definition: confc.c:448
struct m0_mutex s_lock
Definition: sm.h:514
bool m0_conf_fid_is_valid(const struct m0_fid *fid)
Definition: obj.c:378
static struct fdmi_ctx ctx
Definition: main.c:80
#define FID_P(f)
Definition: fid.h:77
M0_INTERNAL void m0_chan_signal_lock(struct m0_chan *chan)
Definition: chan.c:165
struct m0_mutex cc_lock
Definition: confc.h:391
void(* rio_replied)(struct m0_rpc_item *item)
Definition: item.h:300
static void confc_fop_release(struct m0_ref *ref)
Definition: confc.c:1726
void m0_clink_add_lock(struct m0_chan *chan, struct m0_clink *link)
Definition: chan.c:255
uint32_t sd_flags
Definition: sm.h:378
struct m0_rpc_link cc_rlink
Definition: confc.h:407
int32_t m0_rpc_item_error(const struct m0_rpc_item *item)
Definition: item.c:973
#define PRIu32
Definition: types.h:66
static void confc_unlock(struct m0_confc *confc)
Definition: confc.c:1866
#define M0_MAGIX_OFFSET(type, field)
Definition: misc.h:356
static void on_replied(struct m0_rpc_item *item)
Definition: confc.c:1251
M0_BOB_DEFINE(static, &confc_bob, m0_confc)
static bool eop(const struct m0_fid *buf)
Definition: confc.c:1335
M0_INTERNAL void m0_confc_gate_ops_set(struct m0_confc *confc, struct m0_confc_gate_ops *gops)
Definition: confc.c:597
static bool terminal_st_invariant(const struct m0_sm *mach)
Definition: confc.c:1310
struct m0_mutex cc_unatt_guard
Definition: confc.h:446
static struct m0_confc_ctx * mach_to_ctx(struct m0_sm *mach)
Definition: confc.c:1055
static void conf_obj_status_reset(struct m0_confc_ctx *ctx)
Definition: confc.c:1131
#define M0_CNT_INC(cnt)
Definition: arith.h:226
struct m0_clink fc_clink
Definition: confc.h:566
M0_INTERNAL int m0_confstr_parse(const char *str, struct m0_confx **out)
Definition: preload.c:41
static int sm_waiter_wait(struct sm_waiter *w, struct m0_conf_obj **result)
Definition: confc.c:821
void m0_rpc_item_put_lock(struct m0_rpc_item *item)
Definition: item.c:454
static int sm_waiter_init(struct sm_waiter *w, struct m0_confc *confc)
Definition: confc.c:802
#define M0_FI_ENABLED(tag)
Definition: finject.h:231
Definition: fid.h:38
M0_INTERNAL void m0_sm_init(struct m0_sm *mach, const struct m0_sm_conf *conf, uint32_t state, struct m0_sm_group *grp)
Definition: sm.c:313
M0_INTERNAL void m0_rpc_machine_lock(struct m0_rpc_machine *machine)
Definition: rpc_machine.c:551
M0_INTERNAL void m0_confc__open(struct m0_confc_ctx *ctx, struct m0_conf_obj *origin, const struct m0_fid *path)
Definition: confc.c:850
M0_INTERNAL void m0_fop_release(struct m0_ref *ref)
Definition: fop.c:148
static int path_walk_complete(struct m0_confc_ctx *ctx, struct m0_conf_obj *obj, size_t ri)
Definition: confc.c:1406
static int skip_confd_st_in(struct m0_sm *mach)
Definition: confc.c:1166
#define M0_ALLOC_PTR(ptr)
Definition: memory.h:86
struct m0_chan sm_chan
Definition: sm.h:331
M0_INTERNAL void m0_clink_add(struct m0_chan *chan, struct m0_clink *link)
Definition: chan.c:228
const struct m0_rpc_item_ops * ri_ops
Definition: item.h:149
m0_time_t m0_time_from_now(uint64_t secs, long ns)
Definition: time.c:96
const struct m0_fid M0_CONF_ROOT_FID
Definition: root.c:226
static void sm_waiter_fini(struct sm_waiter *w)
Definition: confc.c:814
struct m0_rpc_session * ri_session
Definition: item.h:147
M0_INTERNAL bool m0_confc_invariant(const struct m0_confc *confc)
Definition: confc.c:425
Definition: sm.h:301
static const struct m0_bob_type ctx_bob
Definition: confc.c:417
static void _ast_post(struct m0_sm_ast *ast, void(*cb)(struct m0_sm_group *, struct m0_sm_ast *), int datum)
Definition: confc.c:1519
#define _0C(exp)
Definition: assert.h:311
uint32_t cc_nr_ctx
Definition: confc.h:418
M0_INTERNAL void m0_mutex_fini(struct m0_mutex *mutex)
Definition: mutex.c:42
M0_INTERNAL void m0_clink_fini(struct m0_clink *link)
Definition: chan.c:208
#define IS_IN_ARRAY(idx, array)
Definition: misc.h:311
static int check_st_in(struct m0_sm *mach)
Definition: confc.c:1086
struct m0_rpc_item_type ft_rpc_item_type
Definition: fop.h:235
static struct m0_confc_ctx * ast_to_ctx(struct m0_sm_ast *ast)
Definition: confc.c:1065
static const struct m0_bob_type confc_bob
Definition: confc.c:409
struct m0_fop * m0_rpc_item_to_fop(const struct m0_rpc_item *item)
Definition: fop.c:346
static bool on_object_updated(struct m0_clink *link)
Definition: confc.c:1282
M0_INTERNAL struct m0_confc * m0_confc_from_obj(const struct m0_conf_obj *obj)
Definition: confc.c:592
static struct m0_sm_state_descr confc_ctx_states[S_NR]
Definition: confc.c:319
M0_INTERNAL void m0_confc_close(struct m0_conf_obj *obj)
Definition: confc.c:921
#define M0_CNT_DEC(cnt)
Definition: arith.h:219
#define likely(x)
Definition: assert.h:70
M0_INTERNAL struct m0_rpc_session * m0_confc2sess(struct m0_confc *confc)
Definition: confc.c:1050
struct inode * dir
Definition: dir.c:1028
Definition: nucleus.c:42
static void ctx_state_set(struct m0_confc_ctx *ctx, enum confc_ctx_state state)
Definition: confc.c:1533
M0_INTERNAL int m0_confc_init_wait(struct m0_confc *confc, struct m0_sm_group *sm_group, const char *confd_addr, struct m0_rpc_machine *rpc_mach, const char *local_conf, uint64_t timeout_ns)
Definition: confc.c:512
struct m0_clink w_clink
Definition: confc.c:792
#define M0_FID0
Definition: fid.h:93
static bool failure_st_invariant(const struct m0_sm *mach)
Definition: confc.c:1304
static void disconnect_from_confd(struct m0_confc *confc)
Definition: confc.c:1679
M0_INTERNAL void m0_conf_cache_fini(struct m0_conf_cache *cache)
Definition: cache.c:183
struct m0_rpc_machine * ri_rmachine
Definition: item.h:160
static uint64_t * confc_cache_ver(struct m0_confc_ctx *ctx)
Definition: confc.c:1317
const struct m0_conf_obj_type M0_CONF_DIR_TYPE
Definition: dir.c:206
struct m0_chan cc_unattached
Definition: confc.h:443
struct m0_fop_type m0_conf_fetch_fopt
Definition: fop.c:42
M0_INTERNAL void m0_chan_fini_lock(struct m0_chan *chan)
Definition: chan.c:112
void m0_free(void *data)
Definition: memory.c:146
static void confc_lock(struct m0_confc *confc)
Definition: confc.c:1861
static struct m0_addb2_source * s
Definition: consumer.c:39
M0_INTERNAL int m0_confc_readdir_sync(struct m0_conf_obj *dir, struct m0_conf_obj **pptr)
Definition: confc.c:1020
Definition: confc.c:308
M0_INTERNAL int m0_confc_open_by_fid_sync(struct m0_confc *confc, const struct m0_fid *fid, struct m0_conf_obj **result)
Definition: confc.c:943
static int cached_obj_update(struct m0_confc *confc, const struct m0_confx_obj *flat)
Definition: confc.c:1577
struct m0_pdclust_src_addr src
Definition: fd.c:108
M0_INTERNAL void m0_chan_broadcast(struct m0_chan *chan)
Definition: chan.c:172
int32_t rc
Definition: trigger_fop.h:47
#define ARRAY_SIZE(a)
Definition: misc.h:45
M0_INTERNAL int32_t m0_confc_ctx_error(const struct m0_confc_ctx *ctx)
Definition: confc.c:759
static struct confc_fop * confc_fop_alloc(struct m0_confc_ctx *ctx)
Definition: confc.c:1750
M0_INTERNAL bool m0_conf_obj_invariant(const struct m0_conf_obj *obj)
Definition: obj_ops.c:52
static bool confc_is_locked(const struct m0_confc *confc)
Definition: confc.c:1871
Definition: fop.h:79
#define FID_F
Definition: fid.h:75
Definition: confc.c:316
const struct m0_fid * m0_conf_objx_fid(const struct m0_confx_obj *obj)
Definition: obj_ops.c:266
M0_INTERNAL int m0_confc_readdir(struct m0_confc_ctx *ctx, struct m0_conf_obj *dir, struct m0_conf_obj **pptr)
Definition: confc.c:990
uint64_t fr_ver
Definition: onwire.h:299
#define M0_IMPOSSIBLE(fmt,...)
M0_INTERNAL void m0_sm_fini(struct m0_sm *mach)
Definition: sm.c:331
int32_t fr_rc
Definition: onwire.h:297
#define M0_UNUSED
Definition: misc.h:380