Motr  M0
rconfc.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2013-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 "lib/tlist.h"
27 #include "lib/mutex.h"
28 #include "lib/memory.h" /* M0_ALLOC_PTR, m0_free */
29 #include "lib/errno.h"
30 #include "lib/string.h"
31 #include "lib/buf.h" /* m0_buf_strdup */
32 #include "lib/finject.h" /* M0_FI_ENABLED */
33 #include "motr/magic.h"
34 #include "rm/rm.h"
35 #include "rm/rm_service.h" /* m0_rm_svc_rwlock_get */
36 #include "rpc/conn.h" /* m0_rpc_conn_sessions_cancel */
37 #include "rpc/rpclib.h" /* m0_rpc_client_connect */
38 #include "conf/cache.h"
39 #include "conf/obj_ops.h" /* m0_conf_obj_find */
40 #include "conf/confc.h"
41 #include "conf/helpers.h" /* m0_conf_ha_state_update */
42 #include "conf/rconfc.h"
43 #include "conf/rconfc_internal.h" /* rlock_ctx, rconfc_link,
44  * ver_item, ver_accm */
45 #include "conf/rconfc_link_fom.h" /* rconfc_herd_link__on_death_cb */
46 #include "ha/entrypoint.h" /* m0_ha_entrypoint_client */
47 #include "ha/ha.h" /* m0_ha */
48 #include "ha/epoch.h" /* m0_ha_client_add, m0_ha_client_del */
49 #include "module/instance.h" /* m0_get */
50 
557 static void rconfc_start(struct m0_rconfc *rconfc);
558 static void rconfc_stop_internal(struct m0_rconfc *rconfc);
559 static inline uint32_t rconfc_state(const struct m0_rconfc *rconfc);
560 
561 static bool rconfc_gate_check(struct m0_confc *confc);
562 static int rconfc_gate_skip(struct m0_confc *confc);
563 static bool rconfc_gate_drain(struct m0_clink *clink);
564 static bool ha_clink_cb(struct m0_clink *clink);
565 
568  .go_skip = rconfc_gate_skip,
569  .go_drain = rconfc_gate_drain,
570 };
571 
572 static void rconfc_read_lock_get(struct m0_rconfc *rconfc);
573 static void rconfc_read_lock_complete(struct m0_rm_incoming *in, int32_t rc);
574 static void rconfc_read_lock_conflict(struct m0_rm_incoming *in);
575 
578  .rio_conflict = rconfc_read_lock_conflict,
579 };
580 
581 static struct m0_sm_state_descr rconfc_states[] = {
582  [M0_RCS_INIT] = {
584  .sd_name = "M0_RCS_INIT",
585  .sd_allowed = M0_BITS(M0_RCS_FAILURE,
588  },
590  .sd_name = "M0_RCS_ENTRYPOINT_WAIT",
591  .sd_allowed = M0_BITS(M0_RCS_ENTRYPOINT_WAIT,
594  },
596  .sd_name = "M0_RCS_ENTRYPOINT_CONSUME",
597  .sd_allowed = M0_BITS(M0_RCS_ENTRYPOINT_WAIT,
599  },
601  .sd_name = "M0_RCS_CREDITOR_SETUP",
602  .sd_allowed = M0_BITS(M0_RCS_GET_RLOCK,
604  },
605  [M0_RCS_GET_RLOCK] = {
606  .sd_name = "M0_RCS_GET_RLOCK",
609  },
611  .sd_name = "M0_RCS_VERSION_ELECT",
615  },
616  [M0_RCS_IDLE] = {
617  .sd_name = "M0_RCS_IDLE",
618  .sd_allowed = M0_BITS(M0_RCS_FAILURE, M0_RCS_STOPPING,
620  },
622  .sd_name = "M0_RCS_RLOCK_CONFLICT",
623  .sd_allowed = M0_BITS(M0_RCS_CONDUCTOR_DRAIN),
624  },
626  .sd_name = "M0_RCS_CONDUCTOR_DRAIN",
627  .sd_allowed = M0_BITS(M0_RCS_CONDUCTOR_DISCONNECT,
629  },
631  .sd_name = "M0_RCS_CONDUCTOR_DISCONNECT",
633  },
634  [M0_RCS_STOPPING] = {
635  .sd_name = "M0_RCS_STOPPING",
636  .sd_allowed = M0_BITS(M0_RCS_CONDUCTOR_DRAIN),
637  },
638  [M0_RCS_FAILURE] = {
639  .sd_flags = M0_SDF_FAILURE,
640  .sd_name = "M0_RCS_FAILURE",
641  .sd_allowed = M0_BITS(M0_RCS_STOPPING)
642  },
643  [M0_RCS_FINAL] = {
644  .sd_flags = M0_SDF_TERMINAL,
645  .sd_name = "M0_RCS_FINAL"
646  }
647 };
648 
649 static const struct m0_sm_conf rconfc_sm_conf = {
650  .scf_name = "Rconfc",
651  .scf_nr_states = ARRAY_SIZE(rconfc_states),
652  .scf_state = rconfc_states
653 };
654 
655 /***************************************
656  * List Definitions
657  ***************************************/
658 
659 M0_TL_DESCR_DEFINE(rcnf_herd, "rconfc's working confc list", M0_INTERNAL,
660  struct rconfc_link, rl_herd, rl_magic,
662  );
663 M0_TL_DEFINE(rcnf_herd, M0_INTERNAL, struct rconfc_link);
664 
665 M0_TL_DESCR_DEFINE(rcnf_active, "rconfc's active confc list", M0_INTERNAL,
666  struct rconfc_link, rl_active, rl_magic,
668  );
669 M0_TL_DEFINE(rcnf_active, M0_INTERNAL, struct rconfc_link);
670 
671 /* -------------- Thread for async full conf loading -------------- */
672 
674 {
675  while (rx->rx_ast.run) {
677  m0_sm_group_lock(&rx->rx_grp);
678  m0_sm_asts_run(&rx->rx_grp);
680  }
681 }
682 
684 {
685  M0_SET0(&rx->rx_grp);
686  M0_SET0(&rx->rx_ast);
687  m0_sm_group_init(&rx->rx_grp);
688  rx->rx_ast.run = true;
689  return M0_THREAD_INIT(&rx->rx_ast.thread, struct rconfc_load_ctx *,
690  NULL, &rconfc_load_ast_thread, rx, "rx_ast_thr");
691 }
692 
694 {
695  rx->rx_ast.run = false;
698  m0_sm_group_fini(&rx->rx_grp);
699 }
700 
701 static void rconfc_idle(struct m0_rconfc *rconfc);
702 static void rconfc_fail(struct m0_rconfc *rconfc, int rc);
703 
705  struct m0_sm_ast *ast)
706 {
707  struct m0_rconfc *rconfc = ast->sa_datum;
708 
709  M0_ENTRY("rconfc = %p", rconfc);
711  if (rconfc->rc_rx.rx_rc == 0) {
712  rconfc_idle(rconfc); /* unlock reading gate */
713  } else {
715  }
717  M0_LEAVE();
718 }
719 
721  struct m0_sm_ast *ast)
722 {
723  int rc;
724  struct m0_conf_root *root = NULL;
725  struct m0_rconfc *rconfc = ast->sa_datum;
726  struct m0_confc *confc = &rconfc->rc_confc;
727  struct m0_conf_cache *cache = &confc->cc_cache;
728 
729  M0_ENTRY("rconfc = %p", rconfc);
733  if (root != NULL)
735  /*
736  * The configuration might be loaded. Now we need to invoke
737  * rconfc_ha_restore() to re-associate the kept clinks with their
738  * objects in cache.
739  */
740  rconfc->rc_rx.rx_rc = rc;
743  /* The call to execute in context of group rconfc initialised with */
745  M0_LEAVE();
746 }
747 
748 /***************************************
749  * Helpers
750  ***************************************/
751 
752 /* -------------- Confc Helpers -------------- */
753 
754 static uint64_t _confc_ver_read(const struct m0_confc *confc)
755 {
756  return confc->cc_cache.ca_ver;
757 }
758 
760 static const char *_confc_remote_addr_read(const struct m0_confc *confc)
761 {
762  return m0_confc_is_online(confc) ?
764  NULL;
765 }
766 
767 static int _confc_cache_clean(struct m0_confc *confc)
768 {
769  struct m0_conf_cache *cache = &confc->cc_cache;
770 
771  M0_ENTRY();
773  /* Clear version to prevent version mismatch error after reelection */
774  cache->ca_ver = M0_CONF_VER_UNKNOWN;
782  &confc->cc_root));
783 }
784 
786 {
787  int rc;
788 
789  M0_ENTRY();
793  return M0_RC(rc);
794 }
795 
796 /* ------------------- Phony confc ------------------ */
797 
804 static int _confc_phony_init(struct m0_confc *confc)
805 {
806  void *fake_ptr = (void *)1;
807  int rc;
808 
809  M0_ENTRY();
810  /*
811  * The confc never to do real conf reading, so no real group is
812  * required, as well as no real RPC machine to be used because no RPC
813  * connection to be established. Fake pointers are just to prevent
814  * assertions from firing in m0_confc_init().
815  */
816  rc = m0_confc_init(confc, fake_ptr, NULL, fake_ptr, NULL);
817  if (rc != 0)
818  return M0_ERR(rc);
820  if (rc != 0)
822  return M0_RC(rc);
823 }
824 
830 static void _confc_phony_fini(struct m0_confc *phony)
831 {
832  M0_ENTRY();
833  /* Cache contains only root object */
834  M0_PRE(m0_conf_cache_tlist_length(
835  &phony->cc_cache.ca_registry) == 1);
836  m0_ha_client_del(phony);
837  m0_confc_fini(phony);
838  M0_SET0(phony);
839  M0_LEAVE();
840 }
841 
846  const struct m0_fid *fid)
847 {
848  struct m0_conf_cache *cache = &confc->cc_cache;
849  struct m0_conf_obj *obj;
850  int rc = 0;
851 
852  M0_ENTRY();
855  if (obj != NULL)
856  goto out;
857  rc = -ENOMEM;
859  if (obj == NULL)
860  goto out;
861  /*
862  * fake it be an already normally read object to comply with HA
863  * subscription mechanisms (see ha_state_accept())...
864  */
865  obj->co_status = M0_CS_READY;
866  /*
867  * ...and fake it be pinned, as further discharging will rely on
868  * that pin while iterating the cache
869  */
870  obj->co_nrefs = 1;
872  if (rc != 0) {
873  obj->co_nrefs = 0;
875  }
876 out:
878  return M0_RC(rc);
879 }
880 
886  const struct m0_fid *fid)
887 {
888  struct m0_conf_obj *obj;
889  struct m0_conf_cache *cache = &confc->cc_cache;
890 
891  M0_ENTRY();
895  obj->co_status = M0_CS_MISSING;
896  obj->co_nrefs = 0;
899  M0_LEAVE();
900 }
901 
902 /* -------------- Read lock context ----------------- */
903 
904 static int rlock_ctx_read_domain_init(struct rlock_ctx *rlx)
905 {
906  return m0_rwlockable_domain_type_init(&rlx->rlc_dom, &rlx->rlc_rt);
907 }
908 
909 static void rlock_ctx_read_domain_fini(struct rlock_ctx *rlx)
910 {
912 }
913 
915 {
916  struct rlock_ctx *rlx;
917 
918  rlx = container_of(in, struct rlock_ctx, rlc_req);
919  return rlx->rlc_parent;
920 }
921 
922 static bool rlock_ctx_is_online(struct rlock_ctx *rlx)
923 {
924  return rlx->rlc_rm_addr != NULL;
925 }
926 
927 static void rlock_ctx_disconnect(struct rlock_ctx *rlx)
928 {
929  int rc;
930 
931  M0_ENTRY("rconfc = %p, rlx = %p", rlx->rlc_parent, rlx);
934  if (rc != 0)
935  M0_LOG(M0_ERROR, "Failed to destroy rlock session");
937  if (rc != 0)
938  M0_LOG(M0_ERROR, "Failed to destroy rlock connection");
939  m0_free(rlx->rlc_rm_addr);
940  rlx->rlc_rm_addr = NULL;
941  M0_LEAVE();
942 }
943 
944 static int rlock_ctx_connect(struct rlock_ctx *rlx, const char *ep)
945 {
946  enum {
947  MAX_RPCS_IN_FLIGHT = 15,
948  RLOCK_CTX_TIMEOUT_DEFAULT = 3ULL * M0_TIME_ONE_SECOND,
949  };
950 
951  int rc;
952  m0_time_t deadline = rlx->rlc_timeout == 0 ?
953  m0_time_from_now(0, RLOCK_CTX_TIMEOUT_DEFAULT) :
954  m0_time_from_now(0, rlx->rlc_timeout);
955 
956  M0_ENTRY("rconfc = %p, rlx = %p, ep = %s", rlx->rlc_parent, rlx, ep);
958  M0_PRE(ep != NULL);
959  rlx->rlc_rm_addr = m0_strdup(ep);
960  if (rlx->rlc_rm_addr == NULL)
961  return M0_ERR(-ENOMEM);
962  if (M0_FI_ENABLED("rm_conn_failed"))
963  rc = M0_ERR(-ECONNREFUSED);
964  else
965  rc = m0_rpc_client_connect(&rlx->rlc_conn, &rlx->rlc_sess,
966  rlx->rlc_rmach, rlx->rlc_rm_addr,
967  NULL, MAX_RPCS_IN_FLIGHT, deadline);
968  if (rc != 0) {
969  m0_free(rlx->rlc_rm_addr);
970  rlx->rlc_rm_addr = NULL;
971  }
972  rlx->rlc_online = (rc == 0);
973  /*
974  * It might happen that rconfc was put to M0_RCS_FAILURE state before
975  * connection was established, due to reasons unrelated to RM.
976  */
977  return rconfc_state(rlx->rlc_parent) == M0_RCS_FAILURE ?
978  M0_ERR(-ESTALE) : M0_RC(rc);
979 }
980 
981 static int rlock_ctx_create(struct m0_rconfc *parent,
982  struct m0_rpc_machine *rmach,
983  struct rlock_ctx **out)
984 {
985  struct rlock_ctx *rlx;
986  int rc;
987 
988  M0_ENTRY("rconfc = %p, out = %p", parent, out);
989  M0_PRE(out != NULL);
990  M0_PRE(rmach != NULL);
991 
992  M0_ALLOC_PTR(rlx);
993  if (rlx == NULL)
994  return M0_ERR(-ENOMEM);
995 
996  rlx->rlc_parent = parent;
997  rlx->rlc_rmach = rmach;
999  if (rc != 0)
1000  return M0_ERR(rc);
1004  &rlx->rlc_rwlock, NULL);
1005  rlx->rlc_rm_addr = NULL;
1006  *out = rlx;
1007  return M0_RC(0);
1008 }
1009 
1010 static void rlock_ctx_destroy(struct rlock_ctx *rlx)
1011 {
1012  M0_ENTRY("rconfc = %p, rlx = %p", rlx->rlc_parent, rlx);
1013  M0_PRE(!rlock_ctx_is_online(rlx));
1016  m0_free(rlx);
1017  M0_LEAVE();
1018 }
1019 
1020 static enum m0_rm_owner_state
1022 {
1023  return rlx->rlc_owner.ro_sm.sm_state;
1024 }
1025 
1026 static int rlock_ctx_creditor_setup(struct rlock_ctx *rlx,
1027  const char *ep)
1028 {
1029  struct m0_rm_owner *owner = &rlx->rlc_owner;
1030  struct m0_rm_remote *creditor = &rlx->rlc_creditor;
1031  struct m0_fid *fid = &rlx->rlc_rm_fid;
1032  struct m0_conf_obj *obj;
1033  int rc;
1034 
1035  M0_ENTRY("rconfc = %p, rlx = %p, ep = %s", rlx->rlc_parent, rlx, ep);
1036  M0_PRE(M0_IN(rlock_ctx_creditor_state(rlx),
1038  rc = rlock_ctx_connect(rlx, ep);
1039  if (rc != 0) {
1041  return M0_ERR(rc);
1042  }
1044  creditor->rem_session = &rlx->rlc_sess;
1046  rlx->rlc_rm_fid = *fid;
1047  /*
1048  * Subscribe for HA state changes of creditor.
1049  * Unsubscription is automatically done in m0_rm_remote_fini().
1050  */
1053 
1054  return M0_RC(0);
1055 }
1056 
1057 static void rlock_ctx_creditor_unset(struct rlock_ctx *rlx)
1058 {
1059  M0_ENTRY("rconfc = %p, rlx = %p", rlx->rlc_parent, rlx);
1060  rlock_ctx_disconnect(rlx);
1062  M0_SET0(&rlx->rlc_creditor);
1063  rlx->rlc_owner.ro_creditor = NULL;
1065  M0_LEAVE();
1066 }
1067 
1068 static void rlock_ctx_owner_windup(struct rlock_ctx *rlx)
1069 {
1070  int rc;
1071 
1072  M0_ENTRY("rconfc = %p, rlx = %p", rlx->rlc_parent, rlx);
1076  M0_TIME_NEVER);
1077  M0_ASSERT(rc == 0);
1078  M0_LEAVE();
1079 }
1080 
1081 /* -------------- Quorum calculation context ----------------- */
1082 
1083 static void ver_accm_init(struct ver_accm *va, int total)
1084 {
1085  M0_ENTRY();
1087  M0_SET0(va);
1088  va->va_total = total;
1089  M0_LEAVE();
1090 }
1091 
1092 /* -------------- Rconfc Helpers -------------- */
1093 
1094 static inline uint32_t rconfc_state(const struct m0_rconfc *rconfc)
1095 {
1096  return rconfc->rc_sm.sm_state;
1097 }
1098 
1099 static uint32_t rconfc_confd_count(const char **confd_addr)
1100 {
1101  uint32_t count;
1102 
1103  M0_PRE(confd_addr != NULL);
1104  count = 0;
1105  while (*confd_addr++ != NULL)
1106  ++count;
1107  return count;
1108 }
1109 
1115 {
1116  uint32_t count = rconfc_confd_count(confd_addr);
1117  return m0_forall(i, count,
1118  m0_forall(j, count,
1119  i == j ? true :
1120  !m0_streq(confd_addr[i],
1121  confd_addr[j])));
1122 }
1123 
1124 /***************************************
1125  * Rconfc private part
1126  ***************************************/
1127 
1128 static bool rconfc_is_locked(struct m0_rconfc *rconfc)
1129 {
1131 }
1132 
1135 {
1136  struct rlock_ctx *rlx;
1137 
1138  M0_ENTRY("rconfc = %p", rconfc);
1139  rlx = rconfc->rc_rlock_ctx;
1140  if (!M0_IS0(&rlx->rlc_req)) {
1141  if (!M0_IN(rlx->rlc_req.rin_sm.sm_state,
1143  m0_rm_credit_put(&rlx->rlc_req);
1145  }
1146  M0_SET0(&rlx->rlc_req);
1147  M0_LEAVE();
1148 }
1149 
1150 static void rconfc__ast_post(struct m0_rconfc *rconfc,
1151  void *datum,
1152  void (*cb)(struct m0_sm_group *,
1153  struct m0_sm_ast *))
1154 {
1155  struct m0_sm_ast *ast = &rconfc->rc_ast;
1156 
1157  M0_LOG(M0_DEBUG, "posting AST=%p old %p:%14p:%p new %p:%14p",
1159  cb, datum);
1160 
1161  ast->sa_cb = cb;
1162  ast->sa_datum = datum;
1164 }
1165 
1166 static void rconfc_link_ast_post(struct rconfc_link *lnk,
1167  void *datum,
1168  void (*cb)(struct m0_sm_group *,
1169  struct m0_sm_ast *))
1170 {
1171  struct m0_sm_ast *ast = &lnk->rl_link_ast;
1172  struct m0_rconfc *rconfc = lnk->rl_rconfc;
1173 
1174  ast->sa_cb = cb;
1175  ast->sa_datum = datum;
1177 }
1178 
1179 static void rconfc_ast_post(struct m0_rconfc *rconfc,
1180  void (*cb)(struct m0_sm_group *,
1181  struct m0_sm_ast *))
1182 {
1184 }
1185 
1186 static void rconfc_state_set(struct m0_rconfc *rconfc, int state)
1187 {
1188  M0_LOG(M0_DEBUG, "rconfc: %p, %s -> %s", rconfc,
1190  m0_sm_state_name(&rconfc->rc_sm, state));
1191 
1192  m0_sm_state_set(&rconfc->rc_sm, state);
1193 }
1194 
1195 static void rconfc_fail(struct m0_rconfc *rconfc, int rc)
1196 {
1197  M0_ENTRY("rconfc = %p, rc = %d", rconfc, rc);
1199  M0_LOG(M0_ERROR, "rconfc: %p, state %s failed with %d", rconfc,
1201  /*
1202  * Put read lock on failure, because this rconfc can prevent remote
1203  * write lock requests from completion.
1204  */
1208  if (rconfc->rc_stopping)
1210  if (rconfc->rc_fatal_cb != NULL)
1212  M0_LEAVE();
1213 }
1214 
1216  struct m0_sm_ast *ast)
1217 {
1218  struct m0_rconfc *rconfc = ast->sa_datum;
1219  struct rlock_ctx *rlx = rconfc->rc_rlock_ctx;
1220 
1221  /*
1222  * RPC connection to RM may be lost, or there is no remote RM
1223  * service anymore to respond to read lock request, so need to
1224  * handle this to prevent read lock context from further
1225  * communication attempts
1226  */
1228  if (!M0_FI_ENABLED("rlock_req_failed"))
1231 }
1232 
1233 static void rconfc_fail_ast(struct m0_rconfc *rconfc, int rc)
1234 {
1235  M0_ENTRY();
1236  rconfc->rc_datum = rc;
1238  M0_LEAVE();
1239 }
1240 
1241 M0_INTERNAL bool m0_rconfc_reading_is_allowed(const struct m0_rconfc *rconfc)
1242 {
1243  M0_PRE(rconfc != NULL);
1244  return rconfc_state(rconfc) == M0_RCS_IDLE;
1245 }
1246 
1248 {
1250  return rconfc->rc_ver != M0_CONF_VER_UNKNOWN;
1251 }
1252 
1254 {
1255  struct rconfc_link *lnk;
1256 
1257  /* unlink all active entries */
1258  m0_tl_teardown(rcnf_active, &rconfc->rc_active, lnk) {
1259  rcnf_active_tlink_fini(lnk);
1260  }
1261 }
1262 
1266 static void rconfc_herd_link_subscribe(struct rconfc_link *lnk)
1267 {
1268  struct m0_conf_obj *obj;
1269  struct m0_conf_cache *cache = &lnk->rl_rconfc->rc_phony.cc_cache;
1270 
1271  M0_PRE(lnk->rl_state == CONFC_IDLE);
1273  M0_ASSERT(obj != NULL);
1274  m0_clink_add_lock(&obj->co_ha_chan, &lnk->rl_ha_clink);
1275 }
1276 
1277 static void rconfc_link_fini_ast(struct m0_sm_group *grp,
1278  struct m0_sm_ast *ast);
1283 {
1284  if (lnk->rl_ha_clink.cl_chan != NULL)
1286 }
1287 
1288 static inline struct m0_reqh *rconfc_link2reqh(struct rconfc_link *lnk)
1289 {
1290  return lnk->rl_rconfc->rc_rmach->rm_reqh;
1291 }
1292 
1299 {
1300  struct rconfc_link *lnk = M0_AMB(lnk, clink, rl_ha_clink);
1302 
1303  M0_ENTRY("lnk=%p ep:%s rc %d state:%d", lnk, lnk->rl_confd_addr,
1304  lnk->rl_rc, lnk->rl_state);
1305  M0_ASSERT(m0_fid_eq(&lnk->rl_confd_fid, &obj->co_id));
1306  if (obj->co_ha_state != M0_NC_FAILED) {
1307  M0_LEAVE("co_ha_state = %d, return true", obj->co_ha_state);
1308  return true;
1309  }
1310 
1311  m0_rconfc_lock(lnk->rl_rconfc);
1312  if (!lnk->rl_finalised) {
1314  lnk->rl_finalised = true;
1315  }
1317  M0_LEAVE("lnk=%p co_ha_state = M0_NC_FAILED, return false", lnk);
1318  return false;
1319 }
1320 
1322  struct m0_sm_ast *ast)
1323 {
1324  struct rconfc_link *lnk = ast->sa_datum;
1325 
1326  M0_ENTRY("lnk=%p ep:%s rc %d state:%d", lnk, lnk->rl_confd_addr,
1327  lnk->rl_rc, lnk->rl_state);
1328  m0_rconfc_lock(lnk->rl_rconfc);
1330  if (lnk->rl_state != CONFC_DEAD && !lnk->rl_fom_queued) {
1331  if (lnk->rl_on_state_cb != NULL) /* For UT only */
1332  lnk->rl_on_state_cb(lnk);
1333  lnk->rl_fom_queued = true;
1334  if (m0_clink_is_armed(&lnk->rl_clink)) {
1335  m0_clink_del(&lnk->rl_clink);
1336  m0_clink_fini(&lnk->rl_clink);
1338  }
1341  rconfc_link2reqh(lnk));
1342  m0_fom_queue(&lnk->rl_fom);
1343  M0_LOG(M0_DEBUG, "Created a fom %p to finalize this lnk %p",
1344  &lnk->rl_fom, lnk);
1396  } else {
1397  M0_LOG(M0_INFO, "Link to "FID_F" known to be CONFC_DEAD",
1398  FID_P(&lnk->rl_confd_fid));
1399  }
1400  lnk->rl_finalised = true;
1403 }
1404 
1405 static void rconfc_herd_link_init(struct rconfc_link *lnk)
1406 {
1407  enum { HERD_LINK_TIMEOUT_DEFAULT = 1ULL * M0_TIME_ONE_SECOND };
1408 
1409  struct m0_rconfc *rconfc = lnk->rl_rconfc;
1410 
1411  M0_ENTRY("lnk %p", lnk);
1412  M0_PRE(rconfc != NULL);
1414  if (M0_FI_ENABLED("confc_init"))
1415  lnk->rl_rc = -EIO;
1416  else
1417  lnk->rl_rc =
1419  lnk->rl_confd_addr, rconfc->rc_rmach,
1420  NULL, HERD_LINK_TIMEOUT_DEFAULT);
1421  if (lnk->rl_rc == 0)
1422  lnk->rl_state = CONFC_IDLE;
1423  else
1424  m0_clink_fini(&lnk->rl_ha_clink);
1425  lnk->rl_finalised = false;
1426  M0_LEAVE();
1427 }
1428 
1429 /*
1430  * M0_INTERNAL here is used for the sake of rconfc_herd_link_die() in
1431  * conf/rconfc_link_fom.c
1432  */
1433 M0_INTERNAL void rconfc_herd_link_fini(struct rconfc_link *lnk)
1434 {
1435  M0_ENTRY("lnk %p", lnk);
1437  M0_PRE(lnk->rl_fom_clink.cl_chan == NULL);
1438  M0_PRE(lnk->rl_fom_queued || M0_IS0(&lnk->rl_fom));
1439  /* dead confc has no internals to fini */
1440  if (!M0_IN(lnk->rl_state, (CONFC_DEAD, CONFC_ARMED))) {
1443  &lnk->rl_confd_fid);
1444  m0_clink_fini(&lnk->rl_ha_clink);
1445  if (m0_confc_is_inited(&lnk->rl_confc))
1446  m0_confc_fini(&lnk->rl_confc);
1447  }
1448  M0_LEAVE();
1449 }
1450 
1451 static void rconfc_herd_ast(struct m0_sm_group *grp,
1452  struct m0_sm_ast *ast)
1453 {
1454  M0_LOG(M0_DEBUG, "Re-trying to stop...");
1456 }
1457 
1458 static bool rconfc_herd_fini_cb(struct m0_clink *link)
1459 {
1460  struct m0_rconfc *rconfc = M0_AMB(rconfc, link, rc_herd_cl);
1461  M0_ENTRY("rconfc %p", rconfc);
1462  m0_clink_del(link);
1466  M0_LEAVE();
1467  return true;
1468 }
1469 
1471  struct m0_sm_ast *ast)
1472 {
1473  struct m0_rconfc *rconfc = ast->sa_datum;
1474  struct rlock_ctx *rlx = rconfc->rc_rlock_ctx;
1476  char *rm_addr = hep->hae_active_rm_ep;
1477  int rc = 0;
1478 
1481  M0_LOG(M0_WARN, "rconfc is in a failed state:%p", rconfc);
1482  return;
1483  }
1485 
1486  if (rlx->rlc_rm_addr == NULL || !m0_streq(rlx->rlc_rm_addr, rm_addr)) {
1487  if (rlock_ctx_is_online(rlx))
1490  -EAGAIN;
1491  }
1492  if (rc == 0) {
1494  } else {
1497  }
1498 
1500 }
1501 
1502 static bool rconfc_ha_update_cb(struct m0_clink *link)
1503 {
1504  struct m0_rconfc *rconfc = M0_AMB(rconfc, link, rc_ha_update_cl);
1505  M0_ENTRY("rconfc %p", rconfc);
1506  m0_clink_del(link);
1508  M0_LEAVE();
1509  return true;
1510 }
1511 
1512 static int rconfc_herd_fini(struct m0_rconfc *rconfc)
1513 {
1514  struct rconfc_link *lnk;
1515 
1516  M0_ENTRY("rconfc = %p", rconfc);
1519  m0_tl_for(rcnf_herd, &rconfc->rc_herd, lnk) {
1520  if (lnk->rl_cctx.fc_confc == NULL) {
1521  M0_LOG(M0_DEBUG, "lnk %p ctx is finalised", lnk);
1522  } else if (m0_confc_ctx_is_completed(&lnk->rl_cctx)) {
1523  if (m0_clink_is_armed(&lnk->rl_clink)) {
1524  m0_clink_del(&lnk->rl_clink);
1525  m0_clink_fini(&lnk->rl_clink);
1527  }
1528  } else {
1529  /*
1530  * Found link which conf reading context is still
1531  * active. We need to cancel context operations and wait
1532  * until the context is completed.
1533  */
1534  M0_LOG(M0_DEBUG, "Stop re-trying required (cctx)");
1535  M0_LOG(M0_DEBUG, "adding clink %p to chan %p",
1536  &rconfc->rc_herd_cl,
1537  &lnk->rl_cctx.fc_mach.sm_chan);
1539  &rconfc->rc_herd_cl);
1541  m0_confc2conn(&lnk->rl_confc));
1543  return M0_RC(1);
1544  }
1545  if (lnk->rl_fom_queued) {
1546  /*
1547  * Found link already queued for finalisation. We need
1548  * to wait until FOM finalisation is announced on the
1549  * channel m0_rconfc::rc_herd_chan.
1550  */
1551  M0_LOG(M0_DEBUG, "Stop re-trying required (link FOM)");
1553  &rconfc->rc_herd_cl);
1555  return M0_RC(1);
1556  }
1557  } m0_tl_endfor;
1559  m0_tl_for(rcnf_herd, &rconfc->rc_herd, lnk) {
1560  rconfc_herd_link_fini(lnk);
1561  } m0_tl_endfor;
1562  return M0_RC(0);
1563 }
1564 
1565 static void rconfc_herd_link_destroy(struct rconfc_link *lnk)
1566 {
1567  rcnf_herd_tlink_fini(lnk);
1568  m0_free(lnk->rl_confd_addr);
1569  m0_free(lnk);
1570 }
1571 
1572 M0_INTERNAL void rconfc_herd_link_cleanup(struct rconfc_link *lnk)
1573 {
1574  M0_ENTRY("lnk %p", lnk);
1575  rcnf_herd_tlist_del(lnk);
1576  M0_LEAVE();
1577 }
1578 
1579 static void rconfc_herd_prune(struct m0_rconfc *rconfc)
1580 {
1581  struct rconfc_link *lnk;
1582 
1583  M0_ENTRY("rconfc = %p", rconfc);
1584  m0_tl_teardown(rcnf_herd, &rconfc->rc_herd, lnk)
1586  M0_LEAVE();
1587 }
1588 
1590 {
1591  int rc;
1592 
1593  M0_ENTRY();
1594 
1597  if (rc == 0)
1599 
1600  return M0_RC(rc);
1601 }
1602 
1603 M0_INTERNAL struct rconfc_link *rconfc_herd_find(struct m0_rconfc *rconfc,
1604  const char *addr)
1605 {
1606  M0_PRE(addr != NULL);
1607  return m0_tl_find(rcnf_herd, lnk, &rconfc->rc_herd,
1608  m0_streq(lnk->rl_confd_addr, addr));
1609 }
1610 
1616  const char **confd_addr,
1617  struct m0_fid_arr *confd_fids)
1618 {
1619  struct rconfc_link *lnk;
1620  uint32_t count = rconfc_confd_count(confd_addr);
1621  uint32_t idx;
1622  uint32_t link_quorum = 0;
1623 
1624  M0_ENTRY("rconfc = %p, confd_addr[] = %p, [confd_addr] = %u",
1625  rconfc, confd_addr, count);
1626  M0_PRE(confd_addr != NULL);
1627  M0_PRE(count > 0);
1628  M0_PRE(count == confd_fids->af_count);
1630  M0_PRE(m0_fid_arr_all_unique(confd_fids));
1631 
1632  for (idx = 0; *confd_addr != NULL; confd_addr++, idx++) {
1634  if (lnk == NULL) {
1635  M0_ALLOC_PTR(lnk);
1636  if (lnk == NULL)
1637  goto no_mem;
1638  /* add the allocated element to herd */
1639  lnk->rl_rconfc = rconfc;
1640  lnk->rl_confd_fid = confd_fids->af_elems[idx];
1642  if (lnk->rl_confd_addr == NULL) {
1643  m0_free(lnk);
1644  goto no_mem;
1645  }
1646  lnk->rl_state = CONFC_DEAD;
1647  rcnf_herd_tlink_init_at_tail(lnk, &rconfc->rc_herd);
1648  /* Dead links are destroyed during rm revoke and will
1649  * be created again.
1650  * XXX: rconfc_herd_link_init() can block on waiting
1651  * and this function is called from an AST:
1652  * rconfc_conductor_disconnected_ast() ->
1653  * rconfc_conductor_disconnected() ->
1654  * rconfc_start() ->
1655  * or:
1656  * rlock_owner_clink_cb() ->
1657  * rconfc_owner_creditor_reset() ->
1658  * rconfc_start() ->
1659  * or:
1660  * rconfc_start_ast_cb() ->
1661  * rconfc_start() ->
1662  * rconfc_start_internal() ->
1663  * rconfc_entrypoint_consume() ->
1664  * rconfc_herd_update()
1665  */
1666  rconfc_herd_link_init(lnk);
1667  /*
1668  * only successfully connected @ref rconfc_link gets
1669  * subscribed to HA notifications, and therefore, its
1670  * confd fid is to be added to phony cache
1671  */
1672  if (lnk->rl_state == CONFC_IDLE) {
1674  &rconfc->rc_phony,
1675  &lnk->rl_confd_fid);
1677  } else {
1678  M0_ASSERT(lnk->rl_state == CONFC_DEAD);
1679  }
1680  }
1681  if (lnk->rl_rc == 0)
1682  link_quorum++;
1683  lnk->rl_preserve = true;
1684  }
1685 
1686  M0_LOG(M0_DEBUG, "rconfc: link_quorum = %d rc_quorum = %d",
1687  link_quorum, rconfc->rc_quorum);
1689  m0_tl_for (rcnf_herd, &rconfc->rc_herd, lnk) {
1690  if (!lnk->rl_preserve ||
1691  link_quorum < rconfc->rc_quorum) {
1692  rconfc_herd_link_fini(lnk);
1693  rcnf_herd_tlist_del(lnk);
1695  } else {
1696  /*
1697  * Clean confc cache, so version will be actually
1698  * queried from confd, not extracted from cache.
1699  */
1700  if (!M0_IN(lnk->rl_state, (CONFC_DEAD, CONFC_ARMED)))
1702  lnk->rl_preserve = false;
1703  }
1704  } m0_tl_endfor;
1705  if (link_quorum < rconfc->rc_quorum) {
1706  M0_LOG(M0_DEBUG, "rc_quorum = %d, retrying entrypoint.. ",
1707  rconfc->rc_quorum);
1708  return M0_RC(-EAGAIN);
1709  }
1710  return m0_tl_exists(rcnf_herd, lnk, &rconfc->rc_herd,
1711  lnk->rl_state != CONFC_DEAD) ? M0_RC(0) :
1712  M0_ERR(-ENOENT);
1713 no_mem:
1715  return M0_ERR(-ENOMEM);
1716 }
1717 
1718 static void rconfc_active_add(struct m0_rconfc *rconfc, struct rconfc_link *lnk)
1719 {
1720  if (lnk->rl_state == CONFC_OPEN &&
1722  rcnf_active_tlink_init_at_tail(lnk, &rconfc->rc_active);
1723 }
1724 
1730 {
1731  struct rconfc_link *lnk;
1732 
1733  M0_ENTRY("rconfc = %p", rconfc);
1736  /* re-populate active list */
1737  m0_tl_for(rcnf_herd, &rconfc->rc_herd, lnk) {
1738  rconfc_active_add(rconfc, lnk);
1739  } m0_tl_endfor;
1740  M0_LEAVE();
1741 }
1742 
1748  struct rconfc_link *lnk)
1749 {
1750  /*
1751  * As the conductor is expected to operate on rcnf_active list entries,
1752  * i.e. previously known to be connectable alright, there is no need in
1753  * any lengthy timeout here.
1754  *
1755  * In case active list iteration brings no success, rconfc is just to
1756  * repeat version election starting with ENTRYPOINT request.
1757  */
1758  int rc;
1759  enum { CONDUCTOR_TIMEOUT_DEFAULT = 200ULL * M0_TIME_ONE_MSEC };
1760 
1761  M0_ENTRY("rconfc = %p, lnk = %p, confd_addr = %s", rconfc, lnk,
1762  lnk != NULL ? lnk->rl_confd_addr : "(null)");
1763  M0_PRE(rconfc != NULL);
1764  M0_PRE(lnk != NULL);
1766  /* first use, initialization required */
1770  lnk->rl_confd_addr, rconfc->rc_rmach,
1772  CONDUCTOR_TIMEOUT_DEFAULT) ?:
1774  if (rc != 0)
1775  return M0_ERR(rc);
1776 
1778  }
1779 
1781  lnk->rl_confd_addr));
1782 }
1783 
1800 {
1801  struct rconfc_link *next;
1802  struct rconfc_link *prev;
1803  const char *confd_addr;
1804  int rc;
1805 
1806  M0_ENTRY("rconfc = %p", rconfc);
1807  M0_PRE(rconfc != NULL);
1810  M0_PRE((prev = m0_tl_find(rcnf_active, item, &rconfc->rc_active,
1811  m0_streq(confd_addr, item->rl_confd_addr)))
1812  == NULL || prev->rl_state == CONFC_OPEN);
1813  /* mark items idle except the failed one */
1814  m0_tl_for(rcnf_active, &rconfc->rc_active, next) {
1815  M0_PRE(next->rl_state != CONFC_DEAD);
1816  next->rl_state = m0_streq(confd_addr, next->rl_confd_addr) ?
1818  } m0_tl_endfor;
1819  /* start from the last connected item, or from list tail otherwise */
1820  prev = m0_tl_find(rcnf_active, item, &rconfc->rc_active,
1821  m0_streq(confd_addr, item->rl_confd_addr)) ?:
1822  rcnf_active_tlist_tail(&rconfc->rc_active);
1823  while (1) {
1824  /*
1825  * loop through the list until successful connect or no more
1826  * idle items to try
1827  */
1828  next = rcnf_active_tlist_next(&rconfc->rc_active, prev) ?:
1829  rcnf_active_tlist_head(&rconfc->rc_active);
1830  if (next->rl_state == CONFC_FAILED)
1831  /* this is to start version reelection */
1832  return M0_ERR(-ENOENT);
1834  if (rc == 0 && !M0_FI_ENABLED("conductor_conn_fail")) {
1835  next->rl_state = CONFC_OPEN;
1836  return M0_RC(rc);
1837  }
1838  M0_LOG(M0_ERROR, "Failed to connect to confd_addr = %s rc = %d",
1839  next->rl_confd_addr, rc);
1840  next->rl_state = CONFC_FAILED;
1841  prev = next;
1842  }
1879 }
1880 
1882 {
1883  struct rlock_ctx *rlx;
1884  struct m0_rm_incoming *req;
1885 
1886  M0_ENTRY("rconfc = %p", rconfc);
1888  rlx = rconfc->rc_rlock_ctx;
1889  req = &rlx->rlc_req;
1893  M0_LEAVE();
1894 }
1895 
1896 static void
1898 {
1899  int i;
1900 
1901  M0_LOG(M0_DEBUG, "hbp_quorum=%"PRIu32" confd_nr=%"PRIu32,
1902  entrypoint->hae_quorum, entrypoint->hae_confd_fids.af_count);
1903  M0_LOG(M0_DEBUG, "hbp_active_rm_fid="FID_F" hbp_active_rm_ep=%s",
1904  FID_P(&entrypoint->hae_active_rm_fid),
1905  entrypoint->hae_active_rm_ep);
1906  for (i = 0; entrypoint->hae_confd_eps[i] != NULL; ++i) {
1907  M0_LOG(M0_DEBUG, "hbp_confd_fids[%d]="FID_F
1908  " hbp_confd_eps[%d]=%s",
1909  i, FID_P(&entrypoint->hae_confd_fids.af_elems[i]),
1910  i, entrypoint->hae_confd_eps[i]);
1911  }
1912 }
1913 
1915 {
1916  struct rlock_ctx *rlx = rconfc->rc_rlock_ctx;
1917  struct m0_confc *phony = &rlx->rlc_parent->rc_phony;
1919  int rc;
1920 
1921  M0_ENTRY();
1923  if (hep->hae_control == M0_HA_ENTRYPOINT_QUIT)
1924  /* HA commanded stop querying. No operation permitted. */
1925  return M0_ERR(-EPERM);
1926  if (!m0_fid_is_set(&hep->hae_active_rm_fid))
1927  /*
1928  * The situation when active RM fid is unset cannot happen
1929  * during regular cluster operation. Whichever reason actually
1930  * caused the fid to be zero, it must be considered an
1931  * unrecoverable issue preventing rconfc from further running.
1932  */
1933  return M0_ERR(-ENOKEY);
1934  rconfc->rc_quorum = hep->hae_quorum;
1935  rlx->rlc_rm_fid = hep->hae_active_rm_fid;
1936  M0_LOG(M0_DEBUG, "rm_fid="FID_F, FID_P(&rlx->rlc_rm_fid));
1937  if (hep->hae_active_rm_ep == NULL || hep->hae_active_rm_ep[0] == '\0')
1938  return M0_ERR(-ENOENT);
1940  _confc_phony_cache_append(phony, &rlx->rlc_rm_fid);
1941 
1942  /*
1943  * rconfc SM channel is used for the convenience here:
1944  * 1) No additional channel and mutex structures are required.
1945  * 2) No additional locks are required here since the code is always
1946  * run under the same SM group lock.
1947  * The drawback of this approach is that the threads waiting
1948  * for the SM state change (like at m0_rconfc_start_wait()) will be
1949  * awaken needlessly. But this seems to be harmless.
1950  */
1952 
1954  &hep->hae_confd_fids) ?:
1956  &rconfc->rc_nvec,
1957  &rconfc->rc_sm.sm_chan);
1958 
1959  if (rc != 0) {
1961  return M0_ERR(rc);
1962  }
1963 
1964  return M0_RC(rc);
1965 }
1966 
1968 {
1969  int rc;
1970 
1971  M0_ENTRY();
1972 
1974  if (rc != 0) {
1975  if (M0_IN(rc, (-ENOKEY, -EPERM)))
1976  /* HA requested rconfc to stop querying entrypoint */
1977  rconfc_fail(rconfc, rc);
1978  else
1979  /* rconfc is to keep trying with next entrypoint */
1981  return M0_ERR(rc);
1982  }
1984  return M0_RC(rc);
1985 }
1986 
1987 static void rconfc_start(struct m0_rconfc *rconfc)
1988 {
1989  struct m0_ha *ha = m0_get()->i_ha;
1990  struct m0_ha_entrypoint_client *ecl = &ha->h_entrypoint_client;
1991  int rc = 0;
1992 
1994 
1995  M0_ENTRY();
1996 
1997  while (rconfc_state(rconfc) != M0_RCS_FAILURE) {
1999 
2001  M0_LOG(M0_DEBUG, "Querying ENTRYPOINT...");
2003  break;
2004  }
2005 
2006  M0_LOG(M0_DEBUG, "ENTRYPOINT ready...");
2009  if (rc == 0)
2010  break;
2012  M0_LOG(M0_DEBUG, "Try reconnecting after rc=%d", rc);
2014  }
2015 
2016  M0_LEAVE("rc=%d hae_control=%d is_failed=%s entrypoint_retries=%"PRIu32,
2020 }
2021 
2023  struct m0_sm_ast *ast)
2024 {
2025  struct m0_rconfc *rconfc = ast->sa_datum;
2026 
2027  M0_ENTRY();
2029  M0_LEAVE();
2030 }
2031 
2033  struct m0_sm_ast *ast)
2034 {
2035  struct m0_rconfc *rconfc = ast->sa_datum;
2036 
2037  M0_ENTRY("rconfc = %p", rconfc);
2040  M0_LEAVE();
2041 }
2042 
2044  struct m0_sm_ast *ast)
2045 {
2046  struct m0_rconfc *rconfc = ast->sa_datum;
2047  struct rlock_ctx *rlx = rconfc->rc_rlock_ctx;
2048 
2049  M0_ENTRY("rconfc = %p", rconfc);
2051  /*
2052  * Start conf reelection.
2053  * RM creditor is likely to be changed by HA.
2054  */
2056 
2057  M0_LEAVE();
2058 }
2059 
2060 static bool rlock_owner_clink_cb(struct m0_clink *cl)
2061 {
2062  struct rlock_ctx *rlx = container_of(cl, struct rlock_ctx, rlc_clink);
2063  uint32_t state = rlx->rlc_owner.ro_sm.sm_state;
2064  struct m0_rconfc *rconfc = rlx->rlc_parent;
2065  M0_ENTRY("cl=%p rconfc=%p", cl, rconfc);
2066 
2067  M0_ASSERT(state != ROS_INSOLVENT);
2068  if (state == ROS_DEAD_CREDITOR) {
2070  m0_clink_del(cl);
2071  m0_clink_fini(cl);
2072  }
2073  M0_LEAVE();
2074  return true;
2075 }
2076 
2078 {
2079  struct rlock_ctx *rlx = rconfc->rc_rlock_ctx;
2080  struct m0_rm_owner *owner = &rlx->rlc_owner;
2081 
2082  M0_ENTRY("rconfc= %p ro_sm.sm_state=%d", rconfc, owner->ro_sm.sm_state);
2084  if (owner->ro_sm.sm_state == ROS_DEAD_CREDITOR) {
2086  } else {
2087  /* Wait until owner is in ROS_DEAD_CREDITOR state. */
2089  m0_clink_add(&owner->ro_sm.sm_chan, &rlx->rlc_clink);
2090  }
2091  M0_LEAVE();
2092 }
2093 
2095 {
2096  struct rlock_ctx *rlx = rconfc->rc_rlock_ctx;
2097  struct m0_rm_owner *owner = &rlx->rlc_owner;
2098 
2099  M0_ENTRY("rconfc = %p", rconfc);
2100  /* return read lock back to RM */
2102  /* prepare for version election */
2105  if (rlock_ctx_creditor_state(rlx) != ROS_ACTIVE) {
2106  m0_rm_owner_lock(owner);
2107  /* Creditor is considered dead by HA */
2109  m0_rm_owner_unlock(owner);
2110  } else {
2111  /*
2112  * Start process of conf reelection.
2113  * List of confd or active RM could possibly have changed.
2114  */
2116  }
2117  M0_LEAVE();
2118 }
2119 
2121  struct m0_sm_ast *ast)
2122 {
2123  struct m0_rconfc *rconfc = ast->sa_datum;
2124 
2128 }
2129 
2131 {
2133 
2134  M0_ENTRY("rconfc = %p", rconfc);
2138  M0_LEAVE();
2139  return true;
2140 }
2141 
2143 {
2144  M0_ENTRY("rconfc = %p", rconfc);
2145  /* disconnect confc until read lock being granted */
2153  M0_LEAVE();
2154 }
2155 
2165  struct m0_sm_ast *ast)
2166 {
2167  struct m0_rconfc *rconfc = ast->sa_datum;
2169  struct m0_conf_obj *obj;
2170  int rc = 1;
2171 
2172  M0_ENTRY("rconfc = %p", rconfc);
2174  if ((obj = m0_conf_cache_pinned(cache)) != NULL) {
2175  M0_LOG(M0_DEBUG, "* pinned (%" PRIu64 ") obj "FID_F", "
2176  "waiters %d, ha %d", obj->co_nrefs, FID_P(&obj->co_id),
2177  obj->co_chan.ch_waiters, obj->co_ha_chan.ch_waiters);
2178  m0_clink_add(&obj->co_chan, &rconfc->rc_unpinned_cl);
2179  } else {
2181  if (rc != 0)
2182  rconfc_fail(rconfc, rc);
2183  }
2185 
2186  if (rc == 0)
2189  M0_LEAVE("rc=%d, stopping=%d", rc, rconfc->rc_stopping);
2190 }
2191 
2192 static bool rconfc_unpinned_cb(struct m0_clink *link)
2193 {
2194  struct m0_rconfc *rconfc = container_of(
2195  link, struct m0_rconfc, rc_unpinned_cl);
2196 
2197  M0_ENTRY("rconfc = %p", rconfc);
2199  m0_clink_del(link);
2203  M0_LEAVE();
2204  return false;
2205 }
2206 
2218 static bool rconfc_gate_check(struct m0_confc *confc)
2219 {
2220  struct m0_rconfc *rconfc;
2221  bool result;
2222 
2223  M0_ENTRY("confc = %p", confc);
2224  M0_PRE(confc != NULL);
2226 
2233  M0_TIME_NEVER);
2236  }
2238  M0_LEAVE("result=%s", result ? "true" : "false");
2239  return result;
2240 }
2241 
2247 static int rconfc_gate_skip(struct m0_confc *confc)
2248 {
2249  struct m0_rconfc *rconfc;
2250 
2251  M0_ENTRY("confc = %p", confc);
2252  M0_PRE(confc != NULL);
2255 }
2256 
2263 static bool rconfc_gate_drain(struct m0_clink *clink)
2264 {
2265  struct m0_rconfc *rconfc;
2266  struct m0_confc *confc;
2267 
2268  M0_ENTRY("clink = %p", clink);
2270  rconfc = container_of(confc, struct m0_rconfc, rc_confc);
2273  /*
2274  * Conductor confc has no active confc contexts at this moment,
2275  * so it's safe to call rconfc_ast_drain() in this sm group.
2276  *
2277  * If several rconfc operate in one sm group, then processing
2278  * 'foreign' confc contexts is stopped for some time, but let's live
2279  * with that for now, because no dead-locks are possible.
2280  */
2283  M0_LEAVE();
2284  return false; /* leave this event "unconsumed" */
2285 }
2286 
2288  struct m0_sm_ast *ast)
2289 {
2290  struct m0_rconfc *rconfc = ast->sa_datum;
2291 
2292  M0_ENTRY("rconfc = %p, expired_cb = %p, ready_cb = %p", rconfc,
2295  /* prepare for emptying conductor's cache */
2296  if (rconfc->rc_expired_cb != NULL)
2298  /*
2299  * if no context attached, call it directly, otherwise it is
2300  * going to be called during the very last context finalisation
2301  */
2303  M0_LOG(M0_DEBUG, "rc_confc.cc_nr_ctx = %d", rconfc->rc_confc.cc_nr_ctx);
2304  if (rconfc->rc_confc.cc_nr_ctx == 0) {
2307  } else {
2310  &rconfc->rc_gops);
2311  }
2313  M0_LEAVE();
2314 }
2315 
2317 {
2318  struct rlock_ctx *rlx = rconfc->rc_rlock_ctx;
2319 
2320  M0_ENTRY("rconfc = %p", rconfc);
2333  M0_LEAVE();
2334 }
2335 
2337 {
2338  struct rlock_ctx *rlx = rconfc->rc_rlock_ctx;
2339  int rc;
2340 
2341  M0_ENTRY("rconfc = %p", rconfc);
2343  goto exit;
2344  /*
2345  * This function may be called several times from rconfc_herd_fini_cb().
2346  * It is possible that rconfc already in M0_RCS_STOPPING state.
2347  */
2351  if (rc != 0)
2352  goto exit;
2354  if (rlock_ctx_is_online(rlx))
2359  goto exit;
2360  }
2362 exit:
2363  M0_LEAVE();
2364 }
2365 
2366 static void rconfc_stop_ast_cb(struct m0_sm_group *grp, struct m0_sm_ast *ast)
2367 {
2368  struct m0_rconfc *rconfc = ast->sa_datum;
2369 
2370  M0_ENTRY("rconfc = %p", rconfc);
2372  rconfc->rc_stopping = true;
2373  if (rconfc->rc_expired_cb != NULL)
2376  M0_LEAVE();
2377 }
2378 
2387 {
2388  struct m0_rconfc *rconfc;
2389 
2390  M0_ENTRY("in = %p", in);
2393  M0_LOG(M0_DEBUG, "rconfc_state(rconfc) = %d", rconfc_state(rconfc));
2394  if (rconfc_state(rconfc) == M0_RCS_IDLE) {
2397  } else {
2398  rconfc->rc_rlock_conflict = true;
2399  }
2401  M0_LEAVE();
2402 }
2403 
2404 static void rconfc_idle(struct m0_rconfc *rconfc)
2405 {
2406  M0_ENTRY("rconfc = %p", rconfc);
2408  if (rconfc->rc_stopping) {
2410  M0_LEAVE("Stopped internally");
2411  return;
2412  }
2413  if (rconfc->rc_rlock_conflict) {
2414  rconfc->rc_rlock_conflict = false;
2417  M0_LEAVE("Conflict to be handled...");
2418  return;
2419  }
2420  /*
2421  * If both rc_stopping and rc_rlock_conflict flags aren't set, then
2422  * SM will be idle until read lock conflict is observed provoking
2423  * reelection or user requests stopping rconfc.
2424  */
2426  if (rconfc->rc_ready_cb != NULL)
2428  M0_LEAVE("Idle");
2429 }
2430 
2432 {
2433  struct ver_accm *va = rconfc->rc_qctx;
2434  int ver_count_max;
2435  int armed_count;
2436 
2438  armed_count = m0_tl_reduce(rcnf_herd, lnk, &rconfc->rc_herd, 0,
2439  + (lnk->rl_state == CONFC_ARMED));
2440  ver_count_max = m0_fold(idx, acc, va->va_count, 0,
2441  max_type(int, acc, va->va_items[idx].vi_count));
2442  if (ver_count_max + armed_count < rconfc->rc_quorum) {
2443  M0_LOG(M0_WARN, "No chance left to reach the quorum");
2445  /* Notify consumer about conf expired */
2446  if (rconfc->rc_expired_cb != NULL)
2448  return false;
2449  }
2450  return true;
2451 }
2452 
2457  struct m0_confc *confc)
2458 {
2459  struct ver_accm *va = rconfc->rc_qctx;
2460  struct ver_item *vi = NULL;
2461  uint64_t ver;
2462  int idx;
2463  bool quorum_reached = false;
2464 
2465  M0_ENTRY("rconfc = %p, confc = %p", rconfc, confc);
2466  M0_PRE(va != NULL);
2467  ver = _confc_ver_read(confc);
2469  for (idx = 0; idx < va->va_count; idx++) {
2470  if (va->va_items[idx].vi_ver == ver) {
2471  vi = va->va_items + idx;
2472  break;
2473  }
2474  }
2475  if (vi == NULL) {
2476  /* new version appeared */
2477  M0_ASSERT(va->va_count < va->va_total);
2478  vi = va->va_items + va->va_count;
2479  M0_PRE(vi->vi_ver == 0);
2480  M0_PRE(vi->vi_count == 0);
2481  vi->vi_ver = ver;
2482  ++va->va_count;
2483  }
2484  ++vi->vi_count;
2485 
2486  /* Walk along the herd and see if quorum of any version is reached. */
2487  for (idx = 0; idx < va->va_count; idx++) {
2488  if (va->va_items[idx].vi_count >= rconfc->rc_quorum) {
2489  /* remember the winner */
2490  rconfc->rc_ver = va->va_items[idx].vi_ver;
2491  quorum_reached = true;
2492  break;
2493  }
2494  }
2495  M0_LEAVE("quorum %sreached", quorum_reached ? "" : "not ");
2496  return quorum_reached;
2497 }
2498 
2507 {
2508  int rc = 0;
2509 
2510  M0_ENTRY("rconfc = %p", rconfc);
2511  M0_PRE(rconfc != NULL);
2513  /*
2514  * See if the confc not initialized yet, or having different
2515  * version compared to the newly elected one
2516  */
2519  /* need to connect conductor to a new version confd */
2521  }
2522  return M0_RC(rc);
2523 }
2524 
2529 static void rconfc_cctx_fini(struct m0_sm_group *grp,
2530  struct m0_sm_ast *ast)
2531 {
2532  struct rconfc_link *lnk = ast->sa_datum;
2533 
2534  M0_ASSERT(lnk->rl_state != CONFC_IDLE);
2535  /*
2536  * The context might become complete just at the time
2537  * of rconfc_version_elected() execution and be
2538  * finalised from rconfc_herd_cctxs_fini() already.
2539  */
2540  if (m0_clink_is_armed(&lnk->rl_clink)) {
2541  m0_clink_del(&lnk->rl_clink);
2542  m0_clink_fini(&lnk->rl_clink);
2544  }
2545 }
2546 
2551 {
2552  struct rconfc_link *lnk;
2553 
2554  m0_tl_for (rcnf_herd, &rconfc->rc_herd, lnk) {
2555  /*
2556  * When lnk->fl_fom_queued is true then it means
2557  * that the fom fini is in progress.
2558  */
2559  if (lnk->rl_state == CONFC_DEAD ||
2560  (lnk->rl_fom_queued && lnk->rl_state == CONFC_IDLE ))
2561  /*
2562  * Even with version elected some links may remain dead
2563  * in the herd and require no finalisation. Dead link is
2564  * a link that failed to connect to the respective confd
2565  * during version election.
2566  */
2567  continue;
2568  M0_ASSERT(lnk->rl_state != CONFC_IDLE);
2569  /*
2570  * rconfc_cctx_fini() might be called already for some
2571  * of the contexts (because ASTs are not always executed
2572  * in the same order they were scheduled).
2573  */
2574  M0_LOG(M0_DEBUG, "lnk:%p, rc = %d, ep = %s state:%d", lnk,
2575  lnk->rl_rc, lnk->rl_confd_addr, lnk->rl_state);
2576  if (m0_clink_is_armed(&lnk->rl_clink) &&
2578  m0_clink_del(&lnk->rl_clink);
2579  m0_clink_fini(&lnk->rl_clink);
2581  }
2582  } m0_tl_endfor;
2583  M0_LEAVE();
2584 }
2585 
2587  struct m0_sm_ast *ast)
2588 {
2589  struct m0_rconfc *rconfc = ast->sa_datum;
2590  int rc;
2591 
2593  M0_ENTRY("rconfc = %p", rconfc);
2594 
2596 
2598  rconfc_conductor_engage(rconfc) : -EPROTO;
2599  if (rc != 0) {
2600  M0_ERR_INFO(rc, "re-election started");
2602  if (rc != 0) {
2603  M0_ERR_INFO(rc, "herd_destroy() failed");
2604  goto out;
2605  }
2606  /*
2607  * Start re-election. As version was not elected, the conductor
2608  * never was engaged, and therefore needs no draining...
2609  */
2613  }
2614  /* ... and no disconnection. */
2617  } else {
2618  M0_SET0(&rconfc->rc_rx);
2621  /*
2622  * disable gating operations to let rc_confc read configuration
2623  * before rconfc gets to M0_RCS_IDLE state
2624  */
2626  /* conf load kick-off */
2629  /*
2630  * make conf reading occur in a thread other than standard group
2631  * context rconfc was initialised with
2632  *
2633  * Note: this trick is absolutely temporary, and needs to be
2634  * eliminated later when conf clients learn to handle conf
2635  * updates on their own
2636  */
2639  }
2640 out:
2641  M0_LEAVE();
2642 }
2643 
2658 {
2659  struct rconfc_link *lnk;
2660  struct m0_rconfc *rconfc;
2661  bool quorum_was;
2662  bool quorum_is = false;
2663 
2664  M0_ENTRY("clink = %p", clink);
2665  M0_PRE(clink != NULL);
2666  lnk = container_of(clink, struct rconfc_link, rl_clink);
2667  M0_ASSERT(lnk->rl_state == CONFC_ARMED);
2668  rconfc = lnk->rl_rconfc;
2670 
2671  M0_LOG(M0_DEBUG, "lnk:%p, rc = %d, ep = %s state:%d", lnk, lnk->rl_rc,
2672  lnk->rl_confd_addr, lnk->rl_state);
2673  if (m0_confc_ctx_is_completed(&lnk->rl_cctx)) {
2674  lnk->rl_rc = m0_confc_ctx_error(&lnk->rl_cctx);
2675  if (M0_FI_ENABLED("read_ver_failed")) {
2677  lnk->rl_rc = -ENODATA;
2678  }
2679  lnk->rl_state = lnk->rl_rc == 0 ? CONFC_OPEN : CONFC_FAILED;
2680 
2681  /*
2682  * The code may be called after quorum was already
2683  * reached, so we need to see if it was
2684  */
2685  quorum_was = rconfc_quorum_is_reached(rconfc);
2686 
2687  if (lnk->rl_state == CONFC_FAILED)
2688  M0_LOG(M0_DEBUG, "Lnk failed, rc = %d, ep = %s",
2689  lnk->rl_rc, lnk->rl_confd_addr);
2690  else if (!quorum_was)
2691  quorum_is = rconfc_quorum_test(rconfc, &lnk->rl_confc);
2692 
2693  if (quorum_was)
2694  rconfc_active_add(rconfc, lnk);
2695  else if (quorum_is)
2697 
2698  if (quorum_was) {
2699  struct m0_sm_ast *ast = &rconfc->rc_cctx_fini_ast;
2700  /* A different AST rc_cctx_fini_ast is used here,
2701  * other than the rc_ast, to avoid current access to
2702  * the same AST when triggered concurrently from
2703  * different sources.
2704  */
2705 
2706  M0_LOG(M0_DEBUG, "cctx_fini_ast=%p old cb %p:d %p:n %p "
2707  "new cb %p:d %p",
2708  ast, ast->sa_cb, ast->sa_datum,
2709  ast->sa_next,
2710  &rconfc_cctx_fini, lnk);
2712  ast->sa_datum = lnk;
2714  } else if (quorum_is || !rconfc_quorum_is_possible(rconfc))
2718  }
2719  }
2720  M0_LEAVE();
2721  return true;
2722 }
2723 
2728 static void rconfc_version_elect(struct m0_sm_group *grp, struct m0_sm_ast *ast)
2729 {
2730  struct m0_rconfc *rconfc = ast->sa_datum;
2731  struct ver_accm *va;
2732  struct rconfc_link *lnk;
2733 
2734  M0_ENTRY("rconfc = %p", rconfc);
2735  M0_PRE(rconfc != NULL && rconfc->rc_qctx != NULL);
2736 
2738  va = rconfc->rc_qctx;
2739  M0_PRE(va->va_total != 0);
2740  va->va_count = 0;
2741  m0_forall(idx, va->va_total, M0_SET0(&va->va_items[idx]));
2742  /* query confd instances */
2743  m0_tl_for (rcnf_herd, &rconfc->rc_herd, lnk) {
2744  if (!M0_IN(lnk->rl_state, (CONFC_DEAD, CONFC_ARMED)) &&
2745  lnk->rl_rc == 0 && !lnk->rl_fom_queued) {
2746  m0_confc_ctx_init(&lnk->rl_cctx, &lnk->rl_confc);
2747 
2750  &lnk->rl_clink);
2751  lnk->rl_state = CONFC_ARMED;
2752  m0_confc_open(&lnk->rl_cctx, NULL,
2753  M0_CONF_ROOT_PROFILES_FID);
2754  }
2755  } m0_tl_endfor;
2756  M0_LEAVE();
2757 }
2758 
2765 static void rconfc_read_lock_complete(struct m0_rm_incoming *in, int32_t rc)
2766 {
2767  enum {
2768  MAX_RETRY_COUNT = 100,
2769  };
2770  struct m0_rconfc *rconfc;
2771  struct rlock_ctx *rlx;
2772  static uint32_t retry_count = 0;
2773 
2774  M0_ENTRY("in = %p, rc = %d", in, rc);
2777  rlx = rconfc->rc_rlock_ctx;
2778  if (rc != 0) {
2779  M0_LOG(M0_ERROR, "Read lock request failed with rc = %d", rc);
2780  }
2781 
2782  if (M0_FI_ENABLED("rlock_req_failed"))
2783  rc = M0_ERR(-ESRCH);
2785  if (rc == 0)
2787  else if (rlock_ctx_creditor_state(rlx) == ROS_ACTIVE) {
2788  if (rc == -ECONNREFUSED && retry_count++ < MAX_RETRY_COUNT) {
2790  M0_LOG(M0_DEBUG, "retrying read lock request because of \
2791  connection refused error");
2794  } else {
2796  }
2797  } else
2798  /* Creditor is considered dead by HA */
2801  M0_LEAVE();
2802 }
2803 
2805 {
2806  struct m0_conf_root *root = NULL;
2807  int rc;
2808 
2809  M0_ENTRY("rconfc %p, local_conf = '%s'", rconfc, rconfc->rc_local_conf);
2810  M0_PRE(rconfc->rc_local_conf != NULL && *rconfc->rc_local_conf != '\0');
2816  if (rc != 0) {
2818  rconfc_fail(rconfc, rc);
2819  } else {
2820  M0_ASSERT(root != NULL);
2821  rconfc->rc_ver = root->rt_verno;
2824  if (rc != 0) {
2826  M0_LEAVE("rc=%d", rc);
2827  return M0_RC(rc);
2828  }
2829  if (rconfc->rc_ready_cb != NULL)
2831  }
2833  M0_LEAVE("rc=%d", rc);
2834  return M0_RC(rc);
2835 }
2836 
2837 /**************************************
2838  * Rconfc public interface
2839  **************************************/
2840 
2841 M0_INTERNAL void m0_rconfc_lock(struct m0_rconfc *rconfc)
2842 {
2843  /*
2844  * Don't use m0_sm_group_lock() to ensure that ASTs posted via
2845  * rconfc_ast_post() are executed in well-known context.
2846  * m0_sm_group_lock() has side effect of running ASTs in current context
2847  * after acquiring the mutex.
2848  *
2849  * We use the recursive version of sm group lock, because it might
2850  * be called from ios start sm group AST, which uses the same sm group.
2851  */
2853 }
2854 
2855 M0_INTERNAL void m0_rconfc_unlock(struct m0_rconfc *rconfc)
2856 {
2858 }
2859 
2860 M0_INTERNAL int m0_rconfc_init(struct m0_rconfc *rconfc,
2861  const struct m0_fid *profile,
2862  struct m0_sm_group *sm_group,
2863  struct m0_rpc_machine *rmach,
2864  m0_rconfc_cb_t expired_cb,
2865  m0_rconfc_cb_t ready_cb)
2866 {
2867  int rc;
2868  struct rlock_ctx *rlock_ctx;
2869  struct ver_accm *va;
2870  struct m0_ha *ha;
2871 
2872 
2873  M0_ENTRY("rconfc = %p", rconfc);
2874  M0_PRE(rconfc != NULL);
2875  M0_PRE(rmach != NULL);
2876  M0_PRE(sm_group != NULL);
2877 
2878  M0_SET0(rconfc);
2879 
2880  M0_ALLOC_PTR(va);
2881  if (va == NULL)
2882  return M0_ERR(-ENOMEM);
2883  rc = rlock_ctx_create(rconfc, rmach, &rlock_ctx);
2884  if (rc != 0)
2885  goto rlock_err;
2887  if (rc != 0)
2888  goto confc_err;
2890  rconfc->rc_rmach = rmach;
2891  rconfc->rc_qctx = va;
2893  rconfc->rc_gops = (struct m0_confc_gate_ops) {
2895  .go_skip = m0_rconfc_gate_ops.go_skip,
2896  .go_drain = NULL,
2897  };
2898  rconfc->rc_expired_cb = expired_cb;
2899  rconfc->rc_ready_cb = ready_cb;
2902 
2903  rcnf_herd_tlist_init(&rconfc->rc_herd);
2904  rcnf_active_tlist_init(&rconfc->rc_active);
2910 
2911  /* Subscribe on ha entrypoint callbacks */
2912  ha = m0_get()->i_ha;
2917 
2919 
2920  return M0_RC(0);
2921 confc_err:
2923 rlock_err:
2924  m0_free(va);
2925  return M0_ERR(rc);
2926 }
2927 
2928 M0_INTERNAL int m0_rconfc_start(struct m0_rconfc *rconfc)
2929 {
2930  M0_ENTRY("rconfc = %p, profile = "FID_F, rconfc,
2931  FID_P(&rconfc->rc_profile));
2933  if (rconfc->rc_local_conf != NULL)
2934  return M0_RC(rconfc_local_load(rconfc));
2935 
2939  return M0_RC(0);
2940 }
2941 
2942 M0_INTERNAL int m0_rconfc_start_wait(struct m0_rconfc *rconfc,
2943  uint64_t timeout_ns)
2944 {
2945  struct rlock_ctx *rlx = M0_MEMBER(rconfc, rc_rlock_ctx);
2946  int rc;
2947 
2948  M0_ENTRY("rconfc = %p, profile = "FID_F, rconfc,
2949  FID_P(&rconfc->rc_profile));
2950  if (timeout_ns != M0_TIME_NEVER)
2951  rlx->rlc_timeout = timeout_ns;
2953  if (rc != 0)
2954  return M0_ERR(rc);
2955 
2957  rc = rconfc->rc_sm.sm_rc;
2958  if (rc == 0 && !m0_rconfc_is_preloaded(rconfc)) {
2959  m0_time_t deadline = timeout_ns == M0_TIME_NEVER ?
2960  M0_TIME_NEVER : m0_time_from_now(0, timeout_ns);
2961 
2964  deadline) == -ETIMEDOUT) {
2965  rconfc_fail(rconfc, M0_ERR(-ETIMEDOUT));
2966  }
2967  /*
2968  * Wait mat result in some error (failed to take lock,
2969  * etc). Let's have this under control.
2970  */
2971  rc = rconfc->rc_sm.sm_rc;
2972  }
2973 
2975  return M0_RC(rc);
2976 }
2977 
2978 M0_INTERNAL void m0_rconfc_stop(struct m0_rconfc *rconfc)
2979 {
2980  M0_ENTRY("rconfc %p", rconfc);
2985  /*
2986  * Can't use rconfc_ast_post() here, because this AST can be already
2987  * posted (after observing read lock conflict, for example).
2988  */
2992  M0_LEAVE();
2993 }
2994 
2995 M0_INTERNAL void m0_rconfc_stop_sync(struct m0_rconfc *rconfc)
2996 {
2997  M0_ENTRY("rconfc = %p", rconfc);
2998  if (rconfc_state(rconfc) == M0_RCS_INIT &&
3000  goto leave;
3005 leave:
3006  M0_LEAVE();
3007 }
3008 
3009 M0_INTERNAL void m0_rconfc_fini(struct m0_rconfc *rconfc)
3010 {
3011  M0_ENTRY("rconfc = %p", rconfc);
3012  M0_PRE(rconfc != NULL);
3015 
3018 
3021  /*
3022  * looks like this rconfc instance never was started, so do
3023  * internal cleanup prior to read lock context destruction and
3024  * finalising state machine
3025  */
3034  }
3036  rcnf_active_tlist_fini(&rconfc->rc_active);
3038  rcnf_herd_tlist_fini(&rconfc->rc_herd);
3046  m0_sm_fini(&rconfc->rc_sm);
3048 
3049  M0_LEAVE();
3050 }
3051 
3052 M0_INTERNAL uint64_t m0_rconfc_ver_max_read(struct m0_rconfc *rconfc)
3053 {
3054  uint64_t ver_max;
3055 
3056  M0_ENTRY("rconfc = %p", rconfc);
3059  ver_max = m0_tl_fold(rcnf_herd, lnk, acc, &rconfc->rc_herd,
3061  max64(acc, _confc_ver_read(&lnk->rl_confc)));
3063  M0_LEAVE("ver_max = %"PRIu64, ver_max);
3064  return ver_max;
3065 }
3066 
3067 M0_INTERNAL void m0_rconfc_fatal_cb_set(struct m0_rconfc *rconfc,
3068  m0_rconfc_cb_t cb)
3069 {
3072  rconfc->rc_fatal_cb = cb;
3074  /*
3075  * Failure might occur between successful rconfc start and this
3076  * callback setup. If occurred, callback is fired right away.
3077  */
3078  cb(rconfc);
3079 }
3080 
3082  const char ***eps)
3083 {
3084 
3085  struct rconfc_link *lnk;
3086  size_t confd_eps_length;
3087  int i = 0;
3088 
3090  M0_PRE(*eps == NULL);
3091  confd_eps_length = m0_tlist_length(&rcnf_herd_tl, &rconfc->rc_herd);
3092  M0_ALLOC_ARR(*eps, confd_eps_length + 1);
3093  m0_tl_for(rcnf_herd, &rconfc->rc_herd, lnk) {
3094  (*eps)[i] = m0_strdup(lnk->rl_confd_addr);
3095  if ((*eps)[i] == NULL)
3096  goto fail;
3097  M0_CNT_INC(i);
3098  } m0_tl_endfor;
3099  (*eps)[i] = NULL;
3100  return i;
3101 fail:
3102  m0_strings_free(*eps);
3103  return M0_ERR(-ENOMEM);
3104 }
3105 
3106 M0_INTERNAL int m0_rconfc_rm_endpoint(struct m0_rconfc *rconfc, char **ep)
3107 {
3108  struct rlock_ctx *rlx;
3109 
3111  M0_PRE(_0C(rconfc != NULL) && _0C(rconfc->rc_rlock_ctx != NULL) &&
3113  M0_PRE(*ep == NULL);
3114 
3115  rlx = rconfc->rc_rlock_ctx;
3116  *ep = m0_strdup(rlx->rlc_rm_addr);
3117  if (*ep == NULL)
3118  return M0_ERR(-ENOMEM);
3119  return M0_RC(0);
3120 }
3121 
3122 M0_INTERNAL void m0_rconfc_rm_fid(struct m0_rconfc *rconfc, struct m0_fid *out)
3123 {
3124  struct rlock_ctx *rlx;
3125 
3127  M0_PRE(_0C(rconfc != NULL) && _0C(rconfc->rc_rlock_ctx != NULL) &&
3130 
3131  rlx = rconfc->rc_rlock_ctx;
3132  *out = rlx->rlc_rm_fid;
3133 }
3134 
3135 M0_INTERNAL bool m0_rconfc_is_preloaded(struct m0_rconfc *rconfc)
3136 {
3137  return rconfc_state(rconfc) == M0_RCS_INIT &&
3140 }
3141 
3142 static bool ha_clink_cb(struct m0_clink *clink)
3143 {
3144  struct m0_rconfc *rconfc = container_of(clink,
3145  struct m0_rconfc,
3147  struct m0_ha *ha = m0_get()->i_ha;
3148  struct m0_ha_entrypoint_client *ecl = &ha->h_entrypoint_client;
3149  enum m0_ha_entrypoint_client_state state;
3150  int rc;
3151 
3152  state = m0_ha_entrypoint_client_state_get(ecl);
3153  M0_ENTRY("ha_entrypoint_client_state=%s",
3154  m0_sm_state_name(&ecl->ecl_sm, state));
3155 
3156  if (rconfc->rc_local_conf != NULL)
3157  return true;
3158 
3159  /*
3160  * As there is no external stop event coming to stop rconfc election,
3161  * rconfc re-election can go into a loop with only two confds like in
3162  * LDR-R1 and after a failure of one of the confd, quorum is not possible.
3163  * This is blocking the finalisation of motr processes. To fix this
3164  * issue, during shutdown when HA module in motr process is stopped,
3165  * rconfc is moved to failed state which then can be finalised. Ideally
3166  * rconfc should be stopped by sending shutdown command by external
3167  * entity like HA component.
3168  */
3169  if (state == M0_HEC_STOPPED) {
3171  /* rconfc is not started. */
3172  if (!M0_IN(rconfc_state(rconfc), (M0_RCS_INIT, M0_RCS_FAILURE)))
3173  rconfc_fail(rconfc, -EINVAL);
3175  M0_LEAVE();
3176  return true;
3177  }
3178 
3179  if (state == M0_HEC_AVAILABLE &&
3183  &ecl->ecl_rep);
3184  M0_ASSERT(rc == 0 || rc == -EINVAL);
3185 
3186  if (rc == -EINVAL)
3187  rconfc_fail(rconfc, rc);
3190 
3192  }
3193 
3194  M0_LEAVE();
3195  return true;
3196 }
3197 
3199 #undef M0_TRACE_SUBSYSTEM
3200 
3201 /*
3202  * Local variables:
3203  * c-indentation-style: "K&R"
3204  * c-basic-offset: 8
3205  * tab-width: 8
3206  * fill-column: 80
3207  * scroll-step: 1
3208  * End:
3209  */
struct m0_sm rc_sm
Definition: rconfc.h:247
Definition: beck.c:235
static int rconfc_herd_destroy(struct m0_rconfc *rconfc)
Definition: rconfc.c:1589
const char * rm_addr
struct m0_tl rc_herd
Definition: rconfc.h:333
struct m0_fid hae_active_rm_fid
m0_rconfc_cb_t rc_fatal_cb
Definition: rconfc.h:315
M0_INTERNAL void m0_rconfc_rm_fid(struct m0_rconfc *rconfc, struct m0_fid *out)
Definition: rconfc.c:3122
struct m0_clink rc_conductor_clink
Definition: rconfc.h:418
M0_INTERNAL void m0_chan_wait(struct m0_clink *link)
Definition: chan.c:336
struct m0_conf_obj * cc_root
Definition: confc.h:404
struct m0_fid rlc_rm_fid
void * rc_qctx
Definition: rconfc.h:351
struct rconfc_load_ctx rc_rx
Definition: rconfc.h:399
#define M0_PRE(cond)
struct m0_ha_entrypoint_client h_entrypoint_client
Definition: ha.h:303
#define M0_ALLOC_ARR(arr, nr)
Definition: memory.h:84
M0_INTERNAL struct m0_conf_obj * m0_conf_cache_pinned(const struct m0_conf_cache *cache)
Definition: cache.c:320
static struct m0_rconfc * rlock_ctx_incoming_to_rconfc(struct m0_rm_incoming *in)
Definition: rconfc.c:914
static void rconfc_read_lock_retry(struct m0_sm_group *grp M0_UNUSED, struct m0_sm_ast *ast)
Definition: rconfc.c:2032
M0_INTERNAL void m0_sm_fail(struct m0_sm *mach, int fail_state, int32_t rc)
Definition: sm.c:468
static bool rconfc_gate_check(struct m0_confc *confc)
Definition: rconfc.c:2218
bool rc_stopping
Definition: rconfc.h:355
M0_INTERNAL void m0_mutex_unlock(struct m0_mutex *mutex)
Definition: mutex.c:66
static void rconfc_herd_link_init(struct rconfc_link *lnk)
Definition: rconfc.c:1405
struct m0_clink cc_drain
Definition: confc.h:433
#define m0_strdup(s)
Definition: string.h:43
M0_INTERNAL int m0_ha_entrypoint_rep_copy(struct m0_ha_entrypoint_rep *to, struct m0_ha_entrypoint_rep *from)
struct m0_sm_ast rc_load_fini_ast
Definition: rconfc.h:403
struct m0_clink rc_ha_entrypoint_cl
Definition: rconfc.h:339
static int _confc_phony_cache_append(struct m0_confc *confc, const struct m0_fid *fid)
Definition: rconfc.c:845
char * rc_local_conf
Definition: rconfc.h:390
static void rconfc_link_ast_post(struct rconfc_link *lnk, void *datum, void(*cb)(struct m0_sm_group *, struct m0_sm_ast *))
Definition: rconfc.c:1166
static const struct m0_sm_conf rconfc_sm_conf
Definition: rconfc.c:649
m0_time_t rlc_timeout
#define NULL
Definition: misc.h:38
M0_INTERNAL void m0_clink_init(struct m0_clink *link, m0_chan_cb_t cb)
Definition: chan.c:201
static bool rconfc_gate_drain(struct m0_clink *clink)
Definition: rconfc.c:2263
M0_INTERNAL void m0_clink_del(struct m0_clink *link)
Definition: chan.c:267
struct m0_ha_entrypoint_rep rc_ha_entrypoint_rep
Definition: rconfc.h:420
static struct m0_rm_remote creditor
Definition: file.c:95
M0_INTERNAL void m0_clink_del_lock(struct m0_clink *link)
Definition: chan.c:293
struct m0_rm_remote * ro_creditor
Definition: rm.h:1026
static void rconfc_link_fini_ast(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: rconfc.c:1321
static bool rconfc_unpinned_cb(struct m0_clink *link)
Definition: rconfc.c:2192
struct m0_sm_ast rc_cctx_fini_ast
Definition: rconfc.h:331
static struct m0_reqh * rconfc_link2reqh(struct rconfc_link *lnk)
Definition: rconfc.c:1288
int m0_thread_join(struct m0_thread *q)
Definition: kthread.c:169
M0_INTERNAL int m0_conf_full_load(struct m0_conf_root *r)
Definition: helpers.c:165
void(* sa_cb)(struct m0_sm_group *grp, struct m0_sm_ast *)
Definition: sm.h:506
static void rconfc_start_ast_cb(struct m0_sm_group *grp M0_UNUSED, struct m0_sm_ast *ast)
Definition: rconfc.c:2022
static int rconfc_local_load(struct m0_rconfc *rconfc)
Definition: rconfc.c:2804
void(* rio_complete)(struct m0_rm_incoming *in, int32_t rc)
Definition: rm.h:1493
Definition: sm.h:350
const m0_time_t M0_TIME_NEVER
Definition: time.c:108
M0_INTERNAL void rconfc_herd_link_cleanup(struct rconfc_link *lnk)
Definition: rconfc.c:1572
static struct io_request req
Definition: file.c:100
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
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
uint64_t m0_time_t
Definition: time.h:37
static void rconfc_conductor_drain(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: rconfc.c:2164
#define M0_LOG(level,...)
Definition: trace.h:167
M0_LEAVE()
bool rc_quorum_decision_is_made
Definition: rconfc.h:435
struct m0_sm fc_mach
Definition: confc.h:538
static void rconfc_fail_ast(struct m0_rconfc *rconfc, int rc)
Definition: rconfc.c:1233
const char ** hae_confd_eps
M0_INTERNAL void m0_sm_ast_post(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: sm.c:135
static void rconfc_load_ast_thread(struct rconfc_load_ctx *rx)
Definition: rconfc.c:673
M0_INTERNAL void m0_sm_group_unlock_rec(struct m0_sm_group *grp, bool runast)
Definition: sm.c:123
bool(* go_check)(struct m0_confc *confc)
Definition: confc.h:462
uint32_t rc_ha_entrypoint_retries
Definition: rconfc.h:425
struct rconfc_load_ctx::rconfc_load_ast rx_ast
static void rconfc__ast_post(struct m0_rconfc *rconfc, void *datum, void(*cb)(struct m0_sm_group *, struct m0_sm_ast *))
Definition: rconfc.c:1150
void(* m0_rconfc_cb_t)(struct m0_rconfc *rconfc)
Definition: rconfc.h:215
int(* go_skip)(struct m0_confc *confc)
Definition: confc.h:474
struct m0_ha * i_ha
Definition: instance.h:108
static void rlock_ctx_read_domain_fini(struct rlock_ctx *rlx)
Definition: rconfc.c:909
struct m0_clink s_clink
Definition: sm.h:516
M0_INTERNAL void m0_rm_rwlock_req_init(struct m0_rm_incoming *req, struct m0_rm_owner *owner, const struct m0_rm_incoming_ops *ops, enum m0_rm_incoming_flags flags, enum m0_rm_rwlock_req_type type)
Definition: rm_rwlock.c:548
struct m0_fid * af_elems
Definition: fid.h:45
struct m0_confc * fc_confc
Definition: confc.h:535
M0_INTERNAL int m0_ha_client_del(struct m0_confc *confc)
Definition: epoch.c:232
struct m0_rm_ha_tracker rem_tracker
Definition: rm.h:784
static void leave(struct m0_locality_chore *chore, struct m0_locality *loc, void *place)
Definition: locality.c:315
struct m0_fid rlc_owner_fid
int m0_rpc_session_destroy(struct m0_rpc_session *session, m0_time_t abs_timeout)
Definition: session.c:559
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
static void rconfc_stop_internal(struct m0_rconfc *rconfc)
Definition: rconfc.c:2336
uint32_t rc_quorum
Definition: rconfc.h:258
#define M0_MEMBER(ptr, member)
Definition: misc.h:329
M0_INTERNAL void m0_rconfc_stop_sync(struct m0_rconfc *rconfc)
Definition: rconfc.c:2995
static void rconfc_start(struct m0_rconfc *rconfc)
Definition: rconfc.c:1987
static int _confc_cache_clean_lock(struct m0_confc *confc)
Definition: rconfc.c:785
M0_INTERNAL enum m0_ha_entrypoint_client_state m0_ha_entrypoint_client_state_get(struct m0_ha_entrypoint_client *ecl)
Definition: entrypoint.c:829
M0_INTERNAL void m0_rconfc_fatal_cb_set(struct m0_rconfc *rconfc, m0_rconfc_cb_t cb)
Definition: rconfc.c:3067
M0_INTERNAL const char * m0_sm_state_name(const struct m0_sm *mach, int state)
Definition: sm.c:781
M0_INTERNAL void m0_confc_fini(struct m0_confc *confc)
Definition: confc.c:570
struct ver_item va_items[VERSION_ITEMS_TOTAL_MAX]
static int rlock_ctx_read_domain_init(struct rlock_ctx *rlx)
Definition: rconfc.c:904
M0_INTERNAL bool m0_clink_is_armed(const struct m0_clink *link)
Definition: chan.c:303
m0_rm_owner_state
Definition: rm.h:810
#define M0_BITS(...)
Definition: misc.h:236
static void rconfc_herd_prune(struct m0_rconfc *rconfc)
Definition: rconfc.c:1579
M0_INTERNAL void m0_rm_remote_init(struct m0_rm_remote *rem, struct m0_rm_resource *res)
Definition: rm.c:1411
#define M0_THREAD_INIT(thread, TYPE, init, func, arg, namefmt,...)
Definition: thread.h:139
struct m0_confc_gate_ops rc_gops
Definition: rconfc.h:323
struct m0_rpc_machine * rc_rmach
Definition: rconfc.h:318
M0_INTERNAL struct m0 * m0_get(void)
Definition: instance.c:41
Definition: sm.h:504
uint32_t rc_sm_state_on_abort
Definition: rconfc.h:431
static void rconfc_owner_creditor_reset(struct m0_sm_group *grp M0_UNUSED, struct m0_sm_ast *ast)
Definition: rconfc.c:2043
M0_INTERNAL m0_time_t m0_rpc__down_timeout(void)
Definition: rpc.c:322
static uint32_t rconfc_confd_count(const char **confd_addr)
Definition: rconfc.c:1099
#define container_of(ptr, type, member)
Definition: misc.h:33
static void rconfc_conductor_disconnected(struct m0_rconfc *rconfc)
Definition: rconfc.c:2094
#define M0_SET0(obj)
Definition: misc.h:64
M0_INTERNAL void m0_mutex_lock(struct m0_mutex *mutex)
Definition: mutex.c:49
struct m0_rpc_session * rem_session
Definition: rm.h:755
M0_INTERNAL void m0_ha_entrypoint_client_request(struct m0_ha_entrypoint_client *ecl)
Definition: entrypoint.c:708
struct m0_sm_ast rc_load_ast
Definition: rconfc.h:401
M0_INTERNAL bool m0_fid_is_set(const struct m0_fid *fid)
Definition: fid.c:106
static void rlock_ctx_disconnect(struct rlock_ctx *rlx)
Definition: rconfc.c:927
static struct m0_rpc_item * item
Definition: item.c:56
M0_INTERNAL bool m0_conf_obj_is_stub(const struct m0_conf_obj *obj)
Definition: obj.c:302
M0_INTERNAL void m0_rw_lockable_fini(struct m0_rw_lockable *lockable)
Definition: rm_rwlock.c:523
M0_INTERNAL void m0_sm_group_fini(struct m0_sm_group *grp)
Definition: sm.c:65
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
static m0_bcount_t count
Definition: xcode.c:167
M0_INTERNAL int m0_rm_owner_timedwait(struct m0_rm_owner *owner, uint64_t state, const m0_time_t abs_timeout)
Definition: rm.c:892
#define m0_confc_open(ctx, origin,...)
Definition: confc.h:678
static void rconfc_conf_full_load(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: rconfc.c:720
static void rconfc_read_lock_complete(struct m0_rm_incoming *in, int32_t rc)
Definition: rconfc.c:2765
#define m0_tl_endfor
Definition: tlist.h:700
M0_INTERNAL int m0_sm_timedwait(struct m0_sm *mach, uint64_t states, m0_time_t deadline)
Definition: sm.c:387
static void _confc_phony_cache_remove(struct m0_confc *confc, const struct m0_fid *fid)
Definition: rconfc.c:885
static bool rlock_owner_clink_cb(struct m0_clink *cl)
Definition: rconfc.c:2060
struct m0_fid fid
Definition: di.c:46
return M0_RC(rc)
M0_INTERNAL int m0_confc_root_open(struct m0_confc *confc, struct m0_conf_root **root)
Definition: helpers.c:219
static bool rconfc_ha_update_cb(struct m0_clink *link)
Definition: rconfc.c:1502
Definition: sock.c:754
M0_INTERNAL int m0_rconfc_rm_endpoint(struct m0_rconfc *rconfc, char **ep)
Definition: rconfc.c:3106
M0_INTERNAL const char * m0_rpc_conn_addr(const struct m0_rpc_conn *conn)
Definition: conn.c:1306
struct m0_rm_owner rlc_owner
#define M0_ENTRY(...)
Definition: trace.h:170
struct m0_rw_lockable rlc_rwlock
M0_INTERNAL void m0_rm_rwlock_owner_init(struct m0_rm_owner *owner, struct m0_fid *fid, struct m0_rw_lockable *lockable, struct m0_rm_remote *creditor)
Definition: rm_rwlock.c:532
static struct m0_sm_ast ast[NR]
Definition: locality.c:44
struct m0_rconfc * rlc_parent
M0_INTERNAL void m0_sm_group_unlock(struct m0_sm_group *grp)
Definition: sm.c:96
struct m0_rm_remote rlc_creditor
M0_INTERNAL bool m0_rconfc_reading_is_allowed(const struct m0_rconfc *rconfc)
Definition: rconfc.c:1241
static void _failure_ast_cb(struct m0_sm_group *grp M0_UNUSED, struct m0_sm_ast *ast)
Definition: rconfc.c:1215
uint64_t rc_ver
Definition: rconfc.h:253
void m0_fom_init(struct m0_fom *fom, const struct m0_fom_type *fom_type, const struct m0_fom_ops *ops, struct m0_fop *fop, struct m0_fop *reply, struct m0_reqh *reqh)
Definition: fom.c:1372
int i
Definition: dir.c:1033
struct m0_sm rin_sm
Definition: rm.h:1436
#define PRIu64
Definition: types.h:58
static int64_t max64(int64_t a, int64_t b)
Definition: arith.h:51
static void rconfc_load_ast_thread_fini(struct rconfc_load_ctx *rx)
Definition: rconfc.c:693
#define M0_ERR_INFO(rc, fmt,...)
Definition: trace.h:215
struct m0_sm ro_sm
Definition: rm.h:1005
struct m0_conf_root * root
Definition: note.c:50
struct m0_rpc_machine * rlc_rmach
return M0_ERR(-EOPNOTSUPP)
struct m0_clink rc_ha_update_cl
Definition: rconfc.h:346
static int _confc_cache_clean(struct m0_confc *confc)
Definition: rconfc.c:767
M0_INTERNAL int m0_rpc_client_connect(struct m0_rpc_conn *conn, struct m0_rpc_session *session, struct m0_rpc_machine *rpc_mach, const char *remote_addr, struct m0_fid *svc_fid, uint64_t max_rpcs_in_flight, m0_time_t abs_timeout)
Definition: rpclib.c:102
struct m0_clink rc_herd_cl
Definition: rconfc.h:341
void * sa_datum
Definition: sm.h:508
static void rconfc_herd_link_subscribe(struct rconfc_link *lnk)
Definition: rconfc.c:1266
static const char * _confc_remote_addr_read(const struct m0_confc *confc)
Definition: rconfc.c:760
uint32_t vi_count
uint64_t vi_ver
Definition: trace.h:482
struct m0_confc rc_phony
Definition: rconfc.h:378
static bool rconfc_quorum_is_possible(struct m0_rconfc *rconfc)
Definition: rconfc.c:2431
struct m0_tl ca_registry
Definition: cache.h:99
M0_INTERNAL void m0_rm_rwlock_owner_fini(struct m0_rm_owner *owner)
Definition: rm_rwlock.c:542
static void rconfc_active_populate(struct m0_rconfc *rconfc)
Definition: rconfc.c:1729
bool rc_rlock_conflict
Definition: rconfc.h:360
#define M0_AMB(obj, ptr, field)
Definition: misc.h:320
#define m0_tl_teardown(name, head, obj)
Definition: tlist.h:708
static enum m0_rm_owner_state rlock_ctx_creditor_state(struct rlock_ctx *rlx)
Definition: rconfc.c:1021
struct m0_rm_resource_type rlc_rt
M0_INTERNAL void m0_chan_init(struct m0_chan *chan, struct m0_mutex *ch_guard)
Definition: chan.c:96
M0_INTERNAL void m0_rconfc_stop(struct m0_rconfc *rconfc)
Definition: rconfc.c:2978
#define M0_ASSERT(cond)
M0_INTERNAL const char * m0_bool_to_str(bool b)
Definition: misc.c:207
struct m0_rm_incoming rlc_req
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
Definition: rm.h:828
M0_INTERNAL void m0_sm_group_init(struct m0_sm_group *grp)
Definition: sm.c:53
M0_INTERNAL void m0_fid_tgenerate(struct m0_fid *fid, const uint8_t tid)
Definition: fid.c:155
static void rconfc_cctx_fini(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: rconfc.c:2529
char * rlc_rm_addr
static void rconfc_herd_ast(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: rconfc.c:1451
struct m0_mutex rc_herd_lock
Definition: rconfc.h:410
void m0_sm_state_set(struct m0_sm *mach, int state)
Definition: sm.c:478
M0_INTERNAL void m0_rw_lockable_init(struct m0_rw_lockable *lockable, const struct m0_fid *fid, struct m0_rm_domain *dom)
Definition: rm_rwlock.c:508
struct m0_clink rc_unpinned_cl
Definition: rconfc.h:337
struct m0_rm_domain rlc_dom
static void rconfc_fail(struct m0_rconfc *rconfc, int rc)
Definition: rconfc.c:1195
M0_INTERNAL bool m0_confc_ctx_is_completed(const struct m0_confc_ctx *ctx)
Definition: confc.c:742
static int rlock_ctx_create(struct m0_rconfc *parent, struct m0_rpc_machine *rmach, struct rlock_ctx **out)
Definition: rconfc.c:981
#define m0_streq(a, b)
Definition: string.h:34
static bool rlock_ctx_is_online(struct rlock_ctx *rlx)
Definition: rconfc.c:922
struct m0_tl rc_active
Definition: rconfc.h:335
bool(* go_drain)(struct m0_clink *clink)
Definition: confc.h:481
M0_TL_DEFINE(rcnf_herd, M0_INTERNAL, struct rconfc_link)
static int next[]
Definition: cp.c:248
int m0_rpc_conn_destroy(struct m0_rpc_conn *conn, m0_time_t abs_timeout)
Definition: conn.c:974
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
M0_INTERNAL void m0_rm_rwlock_req_fini(struct m0_rm_incoming *req)
Definition: rm_rwlock.c:567
struct m0_conf_cache cc_cache
Definition: confc.h:394
M0_INTERNAL bool m0_rconfc_is_preloaded(struct m0_rconfc *rconfc)
Definition: rconfc.c:3135
const char * confd_addr[]
static bool ha_clink_cb(struct m0_clink *clink)
Definition: rconfc.c:3142
static void rconfc_creditor_death_handle(struct m0_rconfc *rconfc)
Definition: rconfc.c:2077
static void rlock_ctx_owner_windup(struct rlock_ctx *rlx)
Definition: rconfc.c:1068
struct m0_chan rc_herd_chan
Definition: rconfc.h:416
M0_INTERNAL void m0_clink_signal(struct m0_clink *clink)
Definition: chan.c:326
struct m0_sm_group * sm_grp
Definition: sm.h:321
static void rconfc_ast_post(struct m0_rconfc *rconfc, void(*cb)(struct m0_sm_group *, struct m0_sm_ast *))
Definition: rconfc.c:1179
static void rconfc_state_set(struct m0_rconfc *rconfc, int state)
Definition: rconfc.c:1186
struct m0_fid rc_profile
Definition: rconfc.h:392
M0_INTERNAL void m0_mutex_init(struct m0_mutex *mutex)
Definition: mutex.c:35
M0_INTERNAL size_t m0_tlist_length(const struct m0_tl_descr *d, const struct m0_tl *list)
Definition: tlist.c:117
static int rconfc_start_internal(struct m0_rconfc *rconfc)
Definition: rconfc.c:1967
Definition: fid.h:43
struct m0_confc_gate_ops m0_rconfc_gate_ops
Definition: rconfc.c:566
M0_INTERNAL void rconfc_herd_link_fini(struct rconfc_link *lnk)
Definition: rconfc.c:1433
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
Definition: xcode.h:73
struct m0_chan co_ha_chan
Definition: obj.h:248
static struct m0_sm_state_descr rconfc_states[]
Definition: rconfc.c:581
static int _confc_phony_init(struct m0_confc *confc)
Definition: rconfc.c:804
const struct m0_fid M0_RWLOCK_FID
Definition: rm_rwlock.c:596
M0_INTERNAL void m0_rconfc_lock(struct m0_rconfc *rconfc)
Definition: rconfc.c:2841
struct m0_rm_incoming_ops m0_rconfc_ri_ops
Definition: rconfc.c:576
static void rconfc_read_lock_conflict(struct m0_rm_incoming *in)
Definition: rconfc.c:2386
Definition: reqh.h:94
M0_INTERNAL int m0_conf_confc_ha_update_async(struct m0_confc *confc, struct m0_ha_nvec *nvec, struct m0_chan *chan)
Definition: helpers.c:606
M0_INTERNAL void m0_clink_cleanup(struct m0_clink *link)
Definition: chan.c:310
static bool rconfc_herd_link__on_death_cb(struct m0_clink *clink)
Definition: rconfc.c:1298
int32_t sm_rc
Definition: sm.h:336
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_sm_ast * sa_next
Definition: sm.h:509
struct m0_sm_group rx_grp
Definition: rconfc.h:207
uint64_t rt_verno
Definition: obj.h:390
static void rconfc_conf_load_fini(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: rconfc.c:704
M0_INTERNAL bool m0_confc_is_inited(const struct m0_confc *confc)
Definition: confc.c:448
M0_INTERNAL int m0_rwlockable_domain_type_init(struct m0_rm_domain *rwl_dom, struct m0_rm_resource_type *rwl_rt)
Definition: rm_rwlock.c:256
static struct m0_clink clink[RDWR_REQUEST_MAX]
M0_INTERNAL int m0_conf_cache_add(struct m0_conf_cache *cache, struct m0_conf_obj *obj)
Definition: cache.c:79
static void rconfc_ha_update_ast(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: rconfc.c:1470
#define FID_P(f)
Definition: fid.h:77
static void rconfc_idle(struct m0_rconfc *rconfc)
Definition: rconfc.c:2404
enum m0_ha_entrypoint_control hae_control
struct m0_mutex cc_lock
Definition: confc.h:391
Definition: ha.h:289
static int rconfc_gate_skip(struct m0_confc *confc)
Definition: rconfc.c:2247
static void rconfc_rlock_windup(struct m0_rconfc *rconfc)
Definition: rconfc.c:2316
static void rconfc_read_lock_put(struct m0_rconfc *rconfc)
Definition: rconfc.c:1134
M0_INTERNAL void m0_rconfc_fini(struct m0_rconfc *rconfc)
Definition: rconfc.c:3009
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 void rconfc_herd_cctxs_fini(struct m0_rconfc *rconfc)
Definition: rconfc.c:2550
void m0_clink_add_lock(struct m0_chan *chan, struct m0_clink *link)
Definition: chan.c:255
static uint64_t _confc_ver_read(const struct m0_confc *confc)
Definition: rconfc.c:754
uint32_t sd_flags
Definition: sm.h:378
M0_INTERNAL int m0_rconfc_confd_endpoints(struct m0_rconfc *rconfc, const char ***eps)
Definition: rconfc.c:3081
struct m0_rpc_link cc_rlink
Definition: confc.h:407
static void rlock_ctx_creditor_unset(struct rlock_ctx *rlx)
Definition: rconfc.c:1057
#define PRIu32
Definition: types.h:66
static void rconfc_version_elected(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: rconfc.c:2586
M0_INTERNAL void m0_rm_credit_put(struct m0_rm_incoming *in)
Definition: rm.c:1797
static void rconfc_conductor_disconnected_ast(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: rconfc.c:2120
static uint8_t fail[DATA_UNIT_COUNT_MAX+PARITY_UNIT_COUNT_MAX]
M0_INTERNAL void m0_rconfc_unlock(struct m0_rconfc *rconfc)
Definition: rconfc.c:2855
m0_rconfc_cb_t rc_expired_cb
Definition: rconfc.h:278
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
static bool rconfc__cb_quorum_test(struct m0_clink *clink)
Definition: rconfc.c:2657
static struct m0_fid profile
Definition: rconfc.c:49
M0_INTERNAL void m0_confc_gate_ops_set(struct m0_confc *confc, struct m0_confc_gate_ops *gops)
Definition: confc.c:597
struct m0_rpc_conn rlc_conn
static int rconfc_conductor_connect(struct m0_rconfc *rconfc, struct rconfc_link *lnk)
Definition: rconfc.c:1747
M0_INTERNAL void m0_strings_free(const char **arr)
Definition: string.c:45
static void rconfc_read_lock_get(struct m0_rconfc *rconfc)
Definition: rconfc.c:1881
m0_ha_entrypoint_client_state
Definition: entrypoint.h:86
#define M0_CNT_INC(cnt)
Definition: arith.h:226
static void rconfc_active_all_unlink(struct m0_rconfc *rconfc)
Definition: rconfc.c:1253
#define M0_FI_ENABLED(tag)
Definition: finject.h:231
static int rconfc_conductor_iterate(struct m0_rconfc *rconfc)
Definition: rconfc.c:1799
Definition: fid.h:38
struct m0_ha_nvec rc_nvec
Definition: rconfc.h:348
struct m0_confc rc_confc
Definition: rconfc.h:235
M0_INTERNAL void m0_rm_remote_fini(struct m0_rm_remote *rem)
Definition: rm.c:1431
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
#define M0_IS0(obj)
Definition: misc.h:70
M0_INTERNAL void m0_conf_cache_del(const struct m0_conf_cache *cache, struct m0_conf_obj *obj)
Definition: cache.c:124
struct m0_sm_ast rc_ast
Definition: rconfc.h:325
#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
static int rlock_ctx_connect(struct rlock_ctx *rlx, const char *ep)
Definition: rconfc.c:944
M0_TL_DESCR_DEFINE(rcnf_herd, "rconfc's working confc list", M0_INTERNAL, struct rconfc_link, rl_herd, rl_magic, M0_RCONFC_LINK_MAGIC, M0_RCONFC_HERD_HEAD_MAGIC)
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 rconfc_entrypoint_debug_print(struct m0_ha_entrypoint_rep *entrypoint)
Definition: rconfc.c:1897
Definition: rm.h:863
M0_INTERNAL void m0_rm_owner_windup(struct m0_rm_owner *owner)
Definition: rm.c:930
M0_INTERNAL void m0_ha_entrypoint_rep_free(struct m0_ha_entrypoint_rep *rep)
M0_INTERNAL int m0_rconfc_start(struct m0_rconfc *rconfc)
Definition: rconfc.c:2928
static bool rconfc_confd_addr_are_all_unique(const char **confd_addr)
Definition: rconfc.c:1114
static int rconfc_load_ast_thread_init(struct rconfc_load_ctx *rx)
Definition: rconfc.c:683
static int rconfc_herd_update(struct m0_rconfc *rconfc, const char **confd_addr, struct m0_fid_arr *confd_fids)
Definition: rconfc.c:1615
M0_INTERNAL void m0_conf_obj_delete(struct m0_conf_obj *obj)
Definition: obj_ops.c:167
struct m0_clink rlc_clink
#define _0C(exp)
Definition: assert.h:311
uint32_t cc_nr_ctx
Definition: confc.h:418
static void rconfc_herd_link_unsubscribe(struct rconfc_link *lnk)
Definition: rconfc.c:1282
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
M0_INTERNAL uint64_t m0_rconfc_ver_max_read(struct m0_rconfc *rconfc)
Definition: rconfc.c:3052
static void rconfc_herd_link_destroy(struct rconfc_link *lnk)
Definition: rconfc.c:1565
void * rc_rlock_ctx
Definition: rconfc.h:353
M0_INTERNAL void m0_sm_group_lock(struct m0_sm_group *grp)
Definition: sm.c:83
M0_INTERNAL struct m0_chan * m0_ha_entrypoint_client_chan(struct m0_ha_entrypoint_client *ecl)
Definition: entrypoint.c:823
static int rlock_ctx_creditor_setup(struct rlock_ctx *rlx, const char *ep)
Definition: rconfc.c:1026
static void rconfc_version_elect(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: rconfc.c:2728
M0_INTERNAL void m0_conf_cache_clean(struct m0_conf_cache *cache, const struct m0_conf_obj_type *type)
Definition: cache.c:168
M0_INTERNAL int m0_ha_client_add(struct m0_confc *confc)
Definition: epoch.c:191
M0_INTERNAL void m0_fom_queue(struct m0_fom *fom)
Definition: fom.c:624
M0_INTERNAL void m0_rm_owner_unlock(struct m0_rm_owner *owner)
Definition: rm.c:603
static void ver_accm_init(struct ver_accm *va, int total)
Definition: rconfc.c:1083
static void rlock_ctx_destroy(struct rlock_ctx *rlx)
Definition: rconfc.c:1010
static struct m0_rconfc * rconfc(struct m0_client *m0c)
Definition: client_init.c:310
#define max_type(t, a, b)
Definition: arith.h:82
struct m0_sm_ast rc_stop_ast
Definition: rconfc.h:329
M0_INTERNAL void m0_confc_close(struct m0_conf_obj *obj)
Definition: confc.c:921
static void rconfc_active_add(struct m0_rconfc *rconfc, struct rconfc_link *lnk)
Definition: rconfc.c:1718
static void rlock_conflict_handle(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: rconfc.c:2287
M0_INTERNAL void m0_rm_owner_creditor_reset(struct m0_rm_owner *owner, struct m0_rm_remote *creditor)
Definition: rm.c:904
M0_INTERNAL void m0_chan_fini(struct m0_chan *chan)
Definition: chan.c:104
static void _confc_phony_fini(struct m0_confc *phony)
Definition: rconfc.c:830
static uint32_t rconfc_state(const struct m0_rconfc *rconfc)
Definition: rconfc.c:1094
static bool rconfc_quorum_test(struct m0_rconfc *rconfc, struct m0_confc *confc)
Definition: rconfc.c:2456
static void rconfc_stop_ast_cb(struct m0_sm_group *grp, struct m0_sm_ast *ast)
Definition: rconfc.c:2366
M0_INTERNAL int m0_rconfc_init(struct m0_rconfc *rconfc, const struct m0_fid *profile, struct m0_sm_group *sm_group, struct m0_rpc_machine *rmach, m0_rconfc_cb_t expired_cb, m0_rconfc_cb_t ready_cb)
Definition: rconfc.c:2860
static int total
Definition: base.c:302
struct m0_thread thread
Definition: rconfc.h:210
#define out(...)
Definition: gen.c:41
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
static int rconfc_herd_fini(struct m0_rconfc *rconfc)
Definition: rconfc.c:1512
M0_INTERNAL void m0_rm_owner_lock(struct m0_rm_owner *owner)
Definition: rm.c:592
static void rconfc_conductor_drained(struct m0_rconfc *rconfc)
Definition: rconfc.c:2142
static bool rconfc_quorum_is_reached(struct m0_rconfc *rconfc)
Definition: rconfc.c:1247
#define M0_FID0
Definition: fid.h:93
struct m0_ha_note * nv_note
Definition: note.h:197
struct m0_fid_arr hae_confd_fids
M0_INTERNAL void m0_rpc_conn_sessions_cancel(struct m0_rpc_conn *conn)
Definition: conn.c:1324
static bool rconfc_conductor_disconnect_cb(struct m0_clink *clink)
Definition: rconfc.c:2130
M0_INTERNAL void m0_sm_asts_run(struct m0_sm_group *grp)
Definition: sm.c:150
int rc_datum
Definition: rconfc.h:327
M0_INTERNAL void m0_conf_cache_lock(struct m0_conf_cache *cache)
Definition: cache.c:50
#define m0_tl_find(name, var, head,...)
Definition: tlist.h:757
uint64_t ca_ver
Definition: cache.h:105
#define m0_tl_for(name, head, obj)
Definition: tlist.h:695
void m0_free(void *data)
Definition: memory.c:146
M0_INTERNAL void m0_rwlockable_domain_type_fini(struct m0_rm_domain *rwl_dom, struct m0_rm_resource_type *rwl_rt)
Definition: rm_rwlock.c:267
M0_INTERNAL bool m0_fid_arr_all_unique(const struct m0_fid_arr *a)
Definition: fid.c:327
uint32_t sm_state
Definition: sm.h:307
struct m0_ha_entrypoint_rep ecl_rep
Definition: entrypoint.h:114
struct m0_clink rht_clink
Definition: rm_ha.h:104
static bool rconfc_herd_fini_cb(struct m0_clink *link)
Definition: rconfc.c:1458
int32_t rc
Definition: trigger_fop.h:47
static int rconfc_conductor_engage(struct m0_rconfc *rconfc)
Definition: rconfc.c:2506
struct m0_rpc_session rlc_sess
#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
M0_INTERNAL bool m0_sm_group_is_locked(const struct m0_sm_group *grp)
Definition: sm.c:107
M0_INTERNAL void m0_conf_cache_unlock(struct m0_conf_cache *cache)
Definition: cache.c:55
#define m0_tl_exists(name, var, head,...)
Definition: tlist.h:774
M0_INTERNAL struct rconfc_link * rconfc_herd_find(struct m0_rconfc *rconfc, const char *addr)
Definition: rconfc.c:1603
struct m0_reqh * rm_reqh
Definition: rpc_machine.h:105
m0_rconfc_cb_t rc_ready_cb
Definition: rconfc.h:294
uint32_t af_count
Definition: fid.h:44
M0_INTERNAL void m0_rm_credit_get(struct m0_rm_incoming *in)
Definition: rm.c:1758
struct m0_rm_resource * ro_resource
Definition: rm.h:1015
#define FID_F
Definition: fid.h:75
Definition: trace.h:478
static int rconfc_entrypoint_consume(struct m0_rconfc *rconfc)
Definition: rconfc.c:1914
static bool rconfc_is_locked(struct m0_rconfc *rconfc)
Definition: rconfc.c:1128
M0_INTERNAL void m0_sm_fini(struct m0_sm *mach)
Definition: sm.c:331
#define M0_UNUSED
Definition: misc.h:380
M0_INTERNAL void m0_sm_group_lock_rec(struct m0_sm_group *grp, bool runast)
Definition: sm.c:112
M0_INTERNAL int m0_rconfc_start_wait(struct m0_rconfc *rconfc, uint64_t timeout_ns)
Definition: rconfc.c:2942