Motr  M0
trigger_fom.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2016-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 
30 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_CM
31 #include "cm/cm.h"
32 #include "cm/repreb/trigger_fom.h"
33 #include "cm/repreb/trigger_fop.h"
34 #include "cm/repreb/cm.h"
35 #include "rpc/rpc.h"
36 #include "fop/fom.h"
37 #include "fop/fop.h"
38 #include "fop/fop_item_type.h"
39 #include "lib/trace.h"
40 #include "lib/finject.h"
41 
42 static int trigger_fom_tick(struct m0_fom *fom);
43 static void trigger_fom_fini(struct m0_fom *fom);
44 static size_t trigger_fom_home_locality(const struct m0_fom *fom);
45 static int prepare(struct m0_fom *fom);
46 static int ready(struct m0_fom *fom);
47 static int start(struct m0_fom *fom);
48 
49 static const struct m0_fom_ops trigger_fom_ops = {
51  .fo_tick = trigger_fom_tick,
52  .fo_home_locality = trigger_fom_home_locality
53 };
54 
56  [M0_TPH_PREPARE] = {
57  .sd_name = "Prepare copy machine",
58  .sd_allowed = M0_BITS(M0_TPH_READY, M0_FOPH_INIT,
61  },
62  [M0_TPH_READY] = {
63  .sd_name = "Send ready fops",
64  .sd_allowed = M0_BITS(M0_TPH_START, M0_FOPH_FAILURE)
65  },
66  [M0_TPH_START] = {
67  .sd_name = "Start repair/rebalance",
69  },
70 };
71 
72 const struct m0_sm_conf m0_trigger_conf = {
73  .scf_name = "Trigger",
74  .scf_nr_states = ARRAY_SIZE(m0_trigger_phases),
75  .scf_state = m0_trigger_phases
76 };
77 
78 static int (*trig_action[]) (struct m0_fom *) = {
80  [M0_TPH_READY] = ready,
81  [M0_TPH_START] = start,
82 };
83 
84 M0_INTERNAL int m0_trigger_fom_create(struct m0_trigger_fom *tfom,
85  struct m0_fop *fop,
86  struct m0_reqh *reqh)
87 {
88  struct m0_fom *fom = &tfom->tf_fom;
89  struct m0_fop *rep_fop;
90  uint32_t op;
91  struct m0_fop_type *ft;
92 
93  M0_PRE(fop != NULL);
94  M0_PRE(tfom != NULL);
95  op = m0_fop_opcode(fop);
96  ft = tfom->tf_ops->fto_type(op);
98  if (rep_fop == NULL)
99  return M0_ERR(-ENOMEM);
101  fop, rep_fop, reqh);
102  return M0_RC(0);
103 }
104 
105 static void trigger_fom_fini(struct m0_fom *fom)
106 {
107  M0_PRE(fom != NULL);
108 
109  m0_fom_fini(fom);
110 }
111 
112 static size_t trigger_fom_home_locality(const struct m0_fom *fom)
113 {
114  M0_PRE(fom != NULL);
115 
116  return m0_fop_opcode(fom->fo_fop);
117 }
118 
119 static struct m0_cm *trig2cm(const struct m0_fom *fom)
120 {
121  return container_of(fom->fo_service, struct m0_cm, cm_service);
122 }
123 
124 static struct m0_trigger_fom *trig2tfom(const struct m0_fom *fom)
125 {
126  return container_of(fom, struct m0_trigger_fom, tf_fom);
127 }
128 
129 static void trigger_rep_set(struct m0_fom *fom)
130 {
131  struct m0_fop *rfop = fom->fo_rep_fop;
132  struct trigger_rep_fop *trep = m0_fop_data(rfop);
133  struct m0_cm *cm = trig2cm(fom);
134 
135  trep->rc = cm->cm_mach.sm_rc != 0 ? cm->cm_mach.sm_rc : m0_fom_rc(fom);
136  fom->fo_rep_fop = rfop;
137 }
138 
139 static int trigger_fom_tick(struct m0_fom *fom)
140 {
141  struct trigger_fop *treq = m0_fop_data(fom->fo_fop);
142  struct m0_cm *cm;
143  enum m0_cm_state cm_state;
144  int rc = 0;
145 
146  if (m0_fom_phase(fom) < M0_FOPH_NR) {
147  cm = trig2cm(fom);
148  if (m0_fom_phase(fom) == M0_FOPH_INIT &&
149  treq->op != CM_OP_INVALID) {
150  m0_cm_lock(cm);
151  cm_state = m0_cm_state_get(cm);
152  m0_cm_unlock(cm);
153  /*
154  * Run TPH_PREPARE phase before generic phases. This is
155  * required to prevent dependency between trigger_fom's
156  * and m0_cm_sw_update fom's transactions.
157  */
158  if (M0_IN(cm_state, (M0_CMS_IDLE, M0_CMS_STOP,
159  M0_CMS_FAIL)) ||
160  M0_IN(treq->op, (CM_OP_REPAIR_QUIESCE,
167  return M0_FSO_AGAIN;
168  }
169  }
171  } else
173  if (rc < 0) {
174  if (rc == -EBUSY)
176  else
179  rc = M0_FSO_AGAIN;
180  }
181 
182  return M0_RC(rc);
183 }
184 
185 static int prepare(struct m0_fom *fom)
186 {
187  struct m0_cm *cm = trig2cm(fom);
188  struct trigger_fop *treq = m0_fop_data(fom->fo_fop);
189  enum m0_cm_state cm_state;
190  struct m0_trigger_fom *tfom = trig2tfom(fom);
191  int rc;
192 
193  if (M0_IN(treq->op, (CM_OP_REPAIR_QUIESCE, CM_OP_REBALANCE_QUIESCE))) {
194  /* Set quiesce flag to running copy machine and quit. */
195  cm->cm_quiesce = true;
198  m0_fop_to_rpc_item(fom->fo_rep_fop));
200  return M0_FSO_WAIT;
201  }
202 
203  if (M0_IN(treq->op, (CM_OP_REPAIR_ABORT, CM_OP_REBALANCE_ABORT))) {
204  /* Set abort flag. */
205  m0_cm_lock(cm);
206  /* Its an explicit abort command, no need to transition cm
207  * to failed state.*/
208  m0_cm_abort(cm, 0);
209  m0_cm_unlock(cm);
210  M0_LOG(M0_DEBUG, "GOT ABORT cmd");
213  m0_fop_to_rpc_item(fom->fo_rep_fop));
215  return M0_FSO_WAIT;
216  }
217 
218  m0_cm_lock(cm);
219  cm_state = m0_cm_state_get(cm);
220  m0_cm_unlock(cm);
221 
222  if (M0_IN(treq->op, (CM_OP_REPAIR_STATUS, CM_OP_REBALANCE_STATUS))) {
223  struct m0_fop *rfop = fom->fo_rep_fop;
224  struct m0_status_rep_fop *trep = m0_fop_data(rfop);
225  enum m0_cm_status cm_status;
226 
227  /* Send back status and progress. */
228  M0_LOG(M0_DEBUG, "sending back status for %d: cm state=%d",
229  treq->op, cm_state);
230  switch (cm_state) {
231  case M0_CMS_IDLE:
232  case M0_CMS_STOP:
233  if (cm->cm_quiesce)
234  cm_status = CM_STATUS_PAUSED;
235  else
236  cm_status = CM_STATUS_IDLE;
237  break;
238  case M0_CMS_PREPARE:
239  case M0_CMS_READY:
240  case M0_CMS_ACTIVE:
241  cm_status = CM_STATUS_STARTED;
242  break;
243  case M0_CMS_FAIL:
244  /* Wait for cleanup */
245  if (cm->cm_done && cm->cm_proxy_nr == 0 &&
247  cm_status = CM_STATUS_FAILED;
248  else
249  cm_status = CM_STATUS_STARTED;
250  break;
251  case M0_CMS_FINI:
252  case M0_CMS_INIT:
253  default:
254  cm_status = CM_STATUS_INVALID;
255  break;
256  }
257  trep->ssr_state = cm_status;
258  trep->ssr_progress = tfom->tf_ops->fto_progress(fom, false);
260  m0_fop_to_rpc_item(fom->fo_rep_fop));
262  return M0_FSO_WAIT;
263  }
264 
265  rc = M0_FSO_AGAIN;
266  tfom->tf_ops->fto_prepare(fom);
267  if (M0_IN(cm_state, (M0_CMS_IDLE, M0_CMS_STOP, M0_CMS_FAIL))) {
268  tfom->tf_ops->fto_progress(fom, true);
269  m0_cm_wait(cm, fom);
270  rc = m0_cm_prepare(cm);
271  if (rc == 0) {
273  rc = M0_FSO_WAIT;
274  } else {
276  }
277  } else if (M0_IN(cm_state, (M0_CMS_READY, M0_CMS_ACTIVE))) {
278  /* CM is busy. */
279  rc = -EBUSY;
280  M0_LOG(M0_WARN, "CM is still active, state: %d", cm_state);
281  } else
283  M0_LOG(M0_DEBUG, "got trigger: prepare");
284  return M0_RC(rc);
285 }
286 
287 static int ready(struct m0_fom *fom)
288 {
289  struct m0_cm *cm = trig2cm(fom);
290  int rc;
291 
292  if (M0_FI_ENABLED("no_wait")) {
293  rc = m0_cm_ready(cm);
294  if (rc == 0) {
296  rc = M0_FSO_AGAIN;
297  }
298  return M0_RC(rc);
299  }
300  if (cm->cm_proxy_nr > 0) {
301  m0_cm_lock(cm);
303  m0_cm_unlock(cm);
304  rc = M0_FSO_WAIT;
305  } else
306  rc = M0_FSO_AGAIN;
307  rc = m0_cm_ready(cm) ?: rc;
308  if (rc < 0 && rc != -EAGAIN) {
309  if (cm->cm_proxy_nr > 0)
311  return M0_ERR(rc);
312  }
313  if (rc == -EAGAIN)
314  return M0_FSO_WAIT;
315 
317  M0_LOG(M0_DEBUG, "trigger: ready rc: %d", rc);
318  return rc;
319 }
320 
321 static int start(struct m0_fom *fom)
322 {
323  struct m0_cm *cm = trig2cm(fom);
324  int rc;
325 
326  /*
327  * CM start is potentially blocking operation. For example, DIX
328  * repair/re-balance CM start iterator in separate FOM and waits until
329  * it reaches desired state.
330  */
332  rc = m0_cm_start(cm);
334  if (rc == -EAGAIN) {
335  m0_cm_lock(cm);
337  m0_cm_unlock(cm);
338  return M0_FSO_WAIT;
339  }
340  if (rc != 0)
341  return M0_ERR(rc);
342  M0_LOG(M0_DEBUG, "trigger: start");
345  return M0_FSO_AGAIN;
346 }
347 
348 #ifndef __KERNEL__
349 extern struct m0_sm_state_descr m0_trigger_phases[];
350 extern const struct m0_sm_conf m0_trigger_conf;
351 #endif
352 
353 M0_INTERNAL void m0_cm_trigger_fop_fini(struct m0_fop_type *ft)
354 {
356 }
357 
358 M0_INTERNAL void m0_cm_trigger_fop_init(struct m0_fop_type *ft,
359  enum M0_RPC_OPCODES op,
360  const char *name,
361  const struct m0_xcode_type *xt,
362  uint64_t rpc_flags,
363  struct m0_cm_type *cmt,
364  const struct m0_fom_type_ops *ops)
365 {
366 #ifndef __KERNEL__
369 #endif
370 
372  .name = name,
373  .opcode = op,
374  .xt = xt,
375 #ifndef __KERNEL__
376  .fom_ops = ops,
377  .svc_type = &cmt->ct_stype,
378  .sm = &m0_trigger_conf,
379 #endif
380  .rpc_flags = rpc_flags);
381 }
382 
383 #undef M0_TRACE_SUBSYSTEM
384 
387 /*
388  * Local variables:
389  * c-indentation-style: "K&R"
390  * c-basic-offset: 8
391  * tab-width: 8
392  * fill-column: 80
393  * scroll-step: 1
394  * End:
395  */
396 /*
397  * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap
398  */
m0_cm_status
Definition: cm.h:54
uint32_t m0_fop_opcode(const struct m0_fop *fop)
Definition: fop.c:226
M0_INTERNAL void m0_cm_lock(struct m0_cm *cm)
Definition: cm.c:545
#define M0_PRE(cond)
M0_INTERNAL int m0_trigger_fom_create(struct m0_trigger_fom *tfom, struct m0_fop *fop, struct m0_reqh *reqh)
Definition: trigger_fom.c:84
M0_INTERNAL void m0_fom_block_enter(struct m0_fom *fom)
Definition: fom.c:538
#define NULL
Definition: misc.h:38
M0_RPC_OPCODES
Definition: rpc_opcodes.h:41
bool cm_quiesce
Definition: cm.h:277
static int prepare(struct m0_fom *fom)
Definition: trigger_fom.c:185
#define M0_FOP_TYPE_INIT(ft,...)
Definition: fop.h:307
Definition: sm.h:350
#define M0_LOG(level,...)
Definition: trace.h:167
bool cm_done
Definition: cm.h:265
M0_INTERNAL void m0_cm_wait_cancel(struct m0_cm *cm, struct m0_fom *fom)
Definition: cm.c:1093
static const struct m0_fom_ops trigger_fom_ops
Definition: trigger_fom.c:49
void * m0_fop_data(const struct m0_fop *fop)
Definition: fop.c:220
void m0_fop_type_fini(struct m0_fop_type *fopt)
Definition: fop.c:232
M0_INTERNAL void m0_sm_conf_extend(const struct m0_sm_state_descr *base, struct m0_sm_state_descr *sub, uint32_t nr)
Definition: sm.c:763
static size_t trigger_fom_home_locality(const struct m0_fom *fom)
Definition: trigger_fom.c:112
#define M0_BITS(...)
Definition: misc.h:236
M0_INTERNAL int m0_cm_start(struct m0_cm *cm)
Definition: cm.c:805
#define container_of(ptr, type, member)
Definition: misc.h:33
static struct m0_xcode_type ** xt[]
Definition: protocol.c:64
const struct m0_sm_conf m0_generic_conf
Definition: fom_generic.c:838
uint32_t op
Definition: trigger_fop.h:52
m0_fom_phase
Definition: fom.h:372
struct m0_fom_type ft_fom_type
Definition: fop.h:232
uint64_t ssr_progress
Definition: trigger_fop.h:62
return M0_RC(rc)
static struct m0_cm * cm
Definition: cm.c:63
op
Definition: libdemo.c:64
M0_INTERNAL void m0_cm_unlock(struct m0_cm *cm)
Definition: cm.c:550
static void trigger_rep_set(struct m0_fom *fom)
Definition: trigger_fom.c:129
int opcode
Definition: crate.c:301
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
struct m0_fop_type * f_type
Definition: fop.h:81
m0_cm_state
Definition: cm.h:125
return M0_ERR(-EOPNOTSUPP)
static int(* trig_action[])(struct m0_fom *)
Definition: trigger_fom.c:78
const char * name
Definition: trace.c:110
static void trigger_fom_fini(struct m0_fom *fom)
Definition: trigger_fom.c:105
int m0_fom_tick_generic(struct m0_fom *fom)
Definition: fom_generic.c:848
void m0_fom_fini(struct m0_fom *fom)
Definition: fom.c:1324
const char * scf_name
Definition: sm.h:352
M0_INTERNAL void m0_cm_wait(struct m0_cm *cm, struct m0_fom *fom)
Definition: cm.c:1086
void(* fto_prepare)(struct m0_fom *fom)
Definition: trigger_fom.h:42
void m0_fom_phase_move(struct m0_fom *fom, int32_t rc, int phase)
Definition: fom.c:1699
M0_INTERNAL void m0_cm_trigger_fop_fini(struct m0_fop_type *ft)
Definition: trigger_fom.c:353
uint32_t scf_nr_states
Definition: sm.h:354
M0_INTERNAL void m0_fom_block_leave(struct m0_fom *fom)
Definition: fom.c:582
static struct m0_trigger_fom * trig2tfom(const struct m0_fom *fom)
Definition: trigger_fom.c:124
struct m0_fom tf_fom
Definition: trigger_fom.h:47
Definition: reqh.h:94
int32_t sm_rc
Definition: sm.h:336
Definition: dump.c:103
void m0_rpc_reply_post(struct m0_rpc_item *request, struct m0_rpc_item *reply)
Definition: rpc.c:135
bool swu_is_complete
Definition: sw.h:85
M0_INTERNAL int m0_cm_ready(struct m0_cm *cm)
Definition: cm.c:759
const struct m0_sm_conf m0_trigger_conf
Definition: trigger_fom.c:72
struct m0_fop * m0_fop_reply_alloc(struct m0_fop *req, struct m0_fop_type *rept)
Definition: fop.c:129
Definition: fom.h:481
Definition: cm.h:143
uint32_t ssr_state
Definition: trigger_fop.h:61
uint64_t cm_proxy_nr
Definition: cm.h:250
M0_INTERNAL int m0_cm_prepare(struct m0_cm *cm)
Definition: cm.c:717
struct m0_reqh reqh
Definition: rm_foms.c:48
const char * sd_name
Definition: sm.h:383
struct m0_cm_sw_update cm_sw_update
Definition: cm.h:259
struct m0_sm_state_descr * scf_state
Definition: sm.h:356
m0_trigger_phases
Definition: trigger_fom.h:52
#define M0_FI_ENABLED(tag)
Definition: finject.h:231
uint64_t(* fto_progress)(struct m0_fom *fom, bool reinit_counter)
Definition: trigger_fom.h:41
struct m0_reqh_service cm_service
Definition: cm.h:191
M0_INTERNAL void m0_cm_proxies_init_wait(struct m0_cm *cm, struct m0_fom *fom)
Definition: cm.c:1142
Definition: cm.h:166
M0_INTERNAL int m0_fom_rc(const struct m0_fom *fom)
Definition: fom.c:1727
struct m0_rpc_item * m0_fop_to_rpc_item(const struct m0_fop *fop)
Definition: fop.c:338
static struct m0_cm * trig2cm(const struct m0_fom *fom)
Definition: trigger_fom.c:119
static int start(struct m0_fom *fom)
Definition: trigger_fom.c:321
M0_INTERNAL enum m0_cm_state m0_cm_state_get(const struct m0_cm *cm)
Definition: cm.c:565
static struct m0_fop * fop
Definition: item.c:57
struct m0_reqh_service_type ct_stype
Definition: cm.h:145
const struct m0_fom_trigger_ops * tf_ops
Definition: trigger_fom.h:46
void(* fo_fini)(struct m0_fom *fom)
Definition: fom.h:657
static int ready(struct m0_fom *fom)
Definition: trigger_fom.c:287
static struct m0_fop_type * ft[]
Definition: service_ut.c:856
M0_INTERNAL void m0_cm_trigger_fop_init(struct m0_fop_type *ft, enum M0_RPC_OPCODES op, const char *name, const struct m0_xcode_type *xt, uint64_t rpc_flags, struct m0_cm_type *cmt, const struct m0_fom_type_ops *ops)
Definition: trigger_fom.c:358
void m0_fom_phase_set(struct m0_fom *fom, int phase)
Definition: fom.c:1688
struct m0_sm cm_mach
Definition: cm.h:167
struct m0_fop_type *(* fto_type)(uint32_t op)
Definition: trigger_fom.h:40
M0_INTERNAL void m0_cm_abort(struct m0_cm *cm, int rc)
Definition: cm.c:1181
struct m0_fom_ops ops
Definition: io_foms.c:623
static int trigger_fom_tick(struct m0_fom *fom)
Definition: trigger_fom.c:139
int32_t rc
Definition: trigger_fop.h:47
#define ARRAY_SIZE(a)
Definition: misc.h:45
Definition: fop.h:79
Definition: trace.h:478
struct m0_fop * rep_fop
Definition: dir.c:334