Motr  M0
op.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_BE
24 #include "lib/trace.h"
25 
26 #include "be/op.h"
27 
28 #include "lib/misc.h" /* M0_BITS */
29 #include "fop/fom.h" /* m0_fom_phase_outcome */
30 #include "motr/magic.h" /* M0_BE_OP_SET_MAGIC */
31 
38 M0_TL_DESCR_DEFINE(bos, "m0_be_op::bo_children", static,
39  struct m0_be_op, bo_set_link, bo_set_link_magic,
41 M0_TL_DEFINE(bos, static, struct m0_be_op);
42 
43 static struct m0_sm_state_descr op_states[] = {
44  [M0_BOS_INIT] = {
46  .sd_name = "M0_BOS_INIT",
47  .sd_allowed = M0_BITS(M0_BOS_ACTIVE),
48  },
49  [M0_BOS_ACTIVE] = {
50  .sd_flags = 0,
51  .sd_name = "M0_BOS_ACTIVE",
52  .sd_allowed = M0_BITS(M0_BOS_DONE),
53  },
54  [M0_BOS_DONE] = {
55  .sd_flags = M0_SDF_TERMINAL,
56  .sd_name = "M0_BOS_DONE",
57  .sd_allowed = 0,
58  },
59 };
60 
61 static struct m0_sm_trans_descr op_trans[] = {
62  { "started", M0_BOS_INIT, M0_BOS_ACTIVE },
63  { "completed", M0_BOS_ACTIVE, M0_BOS_DONE },
64 };
65 
66 M0_INTERNAL struct m0_sm_conf op_states_conf = {
67  .scf_name = "m0_be_op::bo_sm",
68  .scf_nr_states = ARRAY_SIZE(op_states),
69  .scf_state = op_states,
70  .scf_trans_nr = ARRAY_SIZE(op_trans),
71  .scf_trans = op_trans
72 };
73 
74 static void be_op_sm_init(struct m0_be_op *op)
75 {
76  m0_sm_init(&op->bo_sm, &op_states_conf, M0_BOS_INIT, &op->bo_sm_group);
77  op->bo_sm.sm_invariant_chk_off = true;
79 }
80 
81 static void be_op_sm_fini(struct m0_be_op *op)
82 {
84  M0_PRE(M0_IN(op->bo_sm.sm_state, (M0_BOS_INIT, M0_BOS_DONE)));
85 
86  if (op->bo_sm.sm_state == M0_BOS_INIT) {
88  m0_sm_state_set(&op->bo_sm, M0_BOS_DONE);
89  }
90  m0_sm_fini(&op->bo_sm);
92 }
93 
94 M0_INTERNAL void m0_be_op_init(struct m0_be_op *op)
95 {
97  m0_sm_group_init(&op->bo_sm_group);
99  bos_tlist_init(&op->bo_children);
100  bos_tlink_init(op);
101  op->bo_parent = NULL;
102  op->bo_is_op_set = false;
103  op->bo_rc = 0;
104  op->bo_rc_is_set = false;
105 }
106 
107 M0_INTERNAL void m0_be_op_fini(struct m0_be_op *op)
108 {
109  bos_tlink_fini(op);
110  bos_tlist_fini(&op->bo_children);
111  be_op_sm_fini(op);
112  m0_sm_group_fini(&op->bo_sm_group);
113 }
114 
115 M0_INTERNAL void m0_be_op_lock(struct m0_be_op *op)
116 {
117  m0_sm_group_lock(op->bo_sm.sm_grp);
118 }
119 
120 M0_INTERNAL void m0_be_op_unlock(struct m0_be_op *op)
121 {
122  m0_sm_group_unlock(op->bo_sm.sm_grp);
123 }
124 
125 M0_INTERNAL bool m0_be_op_is_locked(const struct m0_be_op *op)
126 {
127  return m0_sm_group_is_locked(op->bo_sm.sm_grp);
128 }
129 
130 static void be_op_set_add(struct m0_be_op *parent, struct m0_be_op *child)
131 {
132  M0_PRE(m0_be_op_is_locked(parent));
133  M0_PRE(m0_be_op_is_locked(child));
134 
135  bos_tlist_add_tail(&parent->bo_children, child);
136  child->bo_parent = parent;
137 }
138 
139 static bool be_op_set_del(struct m0_be_op *parent, struct m0_be_op *child)
140 {
141  M0_PRE(m0_be_op_is_locked(parent));
142  M0_PRE(m0_be_op_is_locked(child));
143  M0_PRE(child->bo_parent == parent);
144  M0_PRE(bos_tlist_contains(&parent->bo_children, child));
145 
146  bos_tlist_del(child);
147  child->bo_parent = NULL;
148 
149  return bos_tlist_is_empty(&parent->bo_children);
150 }
151 
152 M0_INTERNAL void m0_be_op_reset(struct m0_be_op *op)
153 {
154  be_op_sm_fini(op);
155  M0_ASSERT(op->bo_parent == NULL);
156  M0_ASSERT(bos_tlist_is_empty(&op->bo_children));
157  op->bo_is_op_set = false;
158  op->bo_rc_is_set = false;
159  op->bo_rc = 0;
160  be_op_sm_init(op);
161 }
162 
163 static void be_op_state_change(struct m0_be_op *op,
164  enum m0_be_op_state state)
165 {
166  struct m0_be_op *parent;
167  m0_be_op_cb_t cb_gc = NULL;
168  void *cb_gc_param;
169  bool state_changed = false;
170  bool last_child = false;
171 
172  /*
173  M0_ENTRY("op=%p state=%s is_op_set=%d",
174  op, m0_sm_state_name(&op->bo_sm, state), !!op->bo_is_op_set);
175  */
176 
177  M0_PRE(M0_IN(state, (M0_BOS_ACTIVE, M0_BOS_DONE)));
178 
179  m0_be_op_lock(op);
180  parent = op->bo_parent;
181  M0_ASSERT(ergo(bos_tlist_is_empty(&op->bo_children),
182  !op->bo_is_op_set || state == M0_BOS_DONE));
183  if (!op->bo_is_op_set ||
184  ((op->bo_sm.sm_state == M0_BOS_INIT && state == M0_BOS_ACTIVE) ||
185  (op->bo_sm.sm_state == M0_BOS_ACTIVE && state == M0_BOS_DONE &&
186  bos_tlist_is_empty(&op->bo_children)))) {
187  /*
188  M0_LOG(M0_DEBUG, "op=%p parent=%p %s -> %s", op, parent,
189  m0_sm_state_name(&op->bo_sm, op->bo_sm.sm_state),
190  m0_sm_state_name(&op->bo_sm, state));
191  */
192  if (parent != NULL && state == M0_BOS_DONE) {
193  /* see m0_be_op_set_add() for the lock order */
194  m0_be_op_lock(parent);
195  last_child = be_op_set_del(parent, op);
196  m0_be_op_unlock(parent);
197  }
198  if (state == M0_BOS_ACTIVE && op->bo_cb_active != NULL)
199  op->bo_cb_active(op, op->bo_cb_active_param);
200  m0_sm_state_set(&op->bo_sm, state);
201  if (state == M0_BOS_DONE && op->bo_cb_done != NULL)
202  op->bo_cb_done(op, op->bo_cb_done_param);
203  if (state == M0_BOS_DONE) {
204  cb_gc = op->bo_cb_gc;
205  cb_gc_param = op->bo_cb_gc_param;
206  }
207  state_changed = true;
208  }
210  /* don't touch the op after the unlock */
211  /* if someone set bo_cb_gc then it's safe to call GC function here */
212  if (cb_gc != NULL)
213  cb_gc(op, cb_gc_param);
214 
215  if (parent != NULL && state_changed &&
216  (state == M0_BOS_ACTIVE || last_child))
217  be_op_state_change(parent, state);
218 }
219 
220 M0_INTERNAL void m0_be_op_active(struct m0_be_op *op)
221 {
222  M0_PRE(!op->bo_is_op_set);
223 
225 }
226 
227 M0_INTERNAL void m0_be_op_done(struct m0_be_op *op)
228 {
229  M0_PRE(!op->bo_is_op_set);
230 
232 }
233 
234 M0_INTERNAL bool m0_be_op_is_done(struct m0_be_op *op)
235 {
236  return op->bo_sm.sm_state == M0_BOS_DONE;
237 }
238 
239 M0_INTERNAL void m0_be_op_callback_set(struct m0_be_op *op,
240  m0_be_op_cb_t cb,
241  void *param,
242  enum m0_be_op_state state)
243 {
244  M0_PRE(M0_IN(state, (M0_BOS_ACTIVE, M0_BOS_DONE, M0_BOS_GC)));
245 
246  switch (state) {
247  case M0_BOS_ACTIVE:
248  M0_ASSERT(op->bo_cb_active == NULL);
249  op->bo_cb_active = cb;
250  op->bo_cb_active_param = param;
251  break;
252  case M0_BOS_DONE:
253  M0_ASSERT(op->bo_cb_done == NULL);
254  op->bo_cb_done = cb;
255  op->bo_cb_done_param = param;
256  break;
257  case M0_BOS_GC:
258  M0_ASSERT(op->bo_cb_gc == NULL);
259  op->bo_cb_gc = cb;
260  op->bo_cb_gc_param = param;
261  break;
262  default:
263  M0_IMPOSSIBLE("invalid state");
264  }
265 }
266 
267 M0_INTERNAL int m0_be_op_tick_ret(struct m0_be_op *op,
268  struct m0_fom *fom,
269  int next_state)
270 {
272 
273  m0_be_op_lock(op);
274  M0_PRE(M0_IN(op->bo_sm.sm_state, (M0_BOS_ACTIVE, M0_BOS_DONE)));
275 
276  if (op->bo_sm.sm_state == M0_BOS_ACTIVE) {
277  ret = M0_FSO_WAIT;
278  m0_fom_wait_on(fom, &op->bo_sm.sm_chan, &fom->fo_cb);
279  }
281 
282  m0_fom_phase_set(fom, next_state);
283  return ret;
284 }
285 
286 M0_INTERNAL void m0_be_op_wait(struct m0_be_op *op)
287 {
288  struct m0_sm *sm = &op->bo_sm;
289  int rc;
290 
291  m0_be_op_lock(op);
293  M0_ASSERT_INFO(rc == 0, "rc=%d", rc);
295 }
296 
297 M0_INTERNAL void m0_be_op_set_add(struct m0_be_op *parent,
298  struct m0_be_op *child)
299 {
300  /* lock order here and in be_op_state_change() should be the same */
301  m0_be_op_lock(child);
302  m0_be_op_lock(parent);
303 
304  M0_ASSERT(parent->bo_sm.sm_state != M0_BOS_DONE);
305  M0_ASSERT( child->bo_sm.sm_state == M0_BOS_INIT);
306 
307  be_op_set_add(parent, child);
308  parent->bo_is_op_set = true;
309 
310  m0_be_op_unlock(parent);
311  m0_be_op_unlock(child);
312 }
313 
314 M0_INTERNAL void m0_be_op_rc_set(struct m0_be_op *op, int rc)
315 {
316  m0_be_op_lock(op);
317  M0_PRE(op->bo_sm.sm_state == M0_BOS_ACTIVE);
318  M0_PRE(!op->bo_rc_is_set);
319  op->bo_rc = rc;
320  op->bo_rc_is_set = true;
322 }
323 
324 M0_INTERNAL int m0_be_op_rc(struct m0_be_op *op)
325 {
326  int rc;
327 
328  m0_be_op_lock(op);
329  M0_PRE(op->bo_sm.sm_state == M0_BOS_DONE);
330  M0_PRE(op->bo_rc_is_set);
331  rc = op->bo_rc;
333  return rc;
334 }
335 
337 #undef M0_TRACE_SUBSYSTEM
338 
339 /*
340  * Local variables:
341  * c-indentation-style: "K&R"
342  * c-basic-offset: 8
343  * tab-width: 8
344  * fill-column: 80
345  * scroll-step: 1
346  * End:
347  */
348 /*
349  * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap
350  */
static struct m0_sm_state_descr op_states[]
Definition: op.c:43
M0_INTERNAL int m0_be_op_rc(struct m0_be_op *op)
Definition: op.c:324
#define M0_PRE(cond)
static void be_op_sm_init(struct m0_be_op *op)
Definition: op.c:74
#define NULL
Definition: misc.h:38
#define ergo(a, b)
Definition: misc.h:293
Definition: sm.h:350
const m0_time_t M0_TIME_NEVER
Definition: time.c:108
M0_INTERNAL void m0_be_op_active(struct m0_be_op *op)
Definition: op.c:220
M0_INTERNAL void m0_be_op_done(struct m0_be_op *op)
Definition: op.c:227
bool bo_is_op_set
Definition: op.h:119
M0_INTERNAL void m0_be_op_wait(struct m0_be_op *op)
Definition: op.c:286
M0_TL_DESCR_DEFINE(bos, "m0_be_op::bo_children", static, struct m0_be_op, bo_set_link, bo_set_link_magic, M0_BE_OP_SET_LINK_MAGIC, M0_BE_OP_SET_MAGIC)
M0_INTERNAL void m0_be_op_unlock(struct m0_be_op *op)
Definition: op.c:120
M0_INTERNAL void m0_fom_wait_on(struct m0_fom *fom, struct m0_chan *chan, struct m0_fom_callback *cb)
Definition: fom.c:1490
#define M0_BITS(...)
Definition: misc.h:236
void(* m0_be_op_cb_t)(struct m0_be_op *op, void *param)
Definition: op.h:72
M0_INTERNAL void m0_be_op_callback_set(struct m0_be_op *op, m0_be_op_cb_t cb, void *param, enum m0_be_op_state state)
Definition: op.c:239
M0_INTERNAL bool m0_sm_addb2_counter_init(struct m0_sm *sm)
Definition: sm.c:891
M0_INTERNAL void m0_be_op_rc_set(struct m0_be_op *op, int rc)
Definition: op.c:314
M0_INTERNAL void m0_sm_group_fini(struct m0_sm_group *grp)
Definition: sm.c:65
struct m0_be_op * bo_parent
Definition: op.h:117
struct m0_tl bo_children
Definition: op.h:111
M0_INTERNAL int m0_sm_timedwait(struct m0_sm *mach, uint64_t states, m0_time_t deadline)
Definition: sm.c:387
op
Definition: libdemo.c:64
M0_INTERNAL void m0_be_op_fini(struct m0_be_op *op)
Definition: op.c:107
M0_INTERNAL void m0_sm_group_unlock(struct m0_sm_group *grp)
Definition: sm.c:96
#define M0_ASSERT(cond)
const char * scf_name
Definition: sm.h:352
M0_INTERNAL void m0_sm_group_init(struct m0_sm_group *grp)
Definition: sm.c:53
void m0_sm_state_set(struct m0_sm *mach, int state)
Definition: sm.c:478
static void be_op_sm_fini(struct m0_be_op *op)
Definition: op.c:81
static struct m0_sm_trans_descr op_trans[]
Definition: op.c:61
static void be_op_set_add(struct m0_be_op *parent, struct m0_be_op *child)
Definition: op.c:130
m0_be_op_state
Definition: op.h:55
Definition: dump.c:103
static bool be_op_set_del(struct m0_be_op *parent, struct m0_be_op *child)
Definition: op.c:139
M0_INTERNAL struct m0_sm_conf op_states_conf
Definition: op.c:66
M0_INTERNAL void m0_be_op_init(struct m0_be_op *op)
Definition: op.c:94
uint32_t sd_flags
Definition: sm.h:378
Definition: fom.h:481
M0_INTERNAL void m0_be_op_reset(struct m0_be_op *op)
Definition: op.c:152
m0_fom_phase_outcome
Definition: fom.h:625
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 int m0_be_op_tick_ret(struct m0_be_op *op, struct m0_fom *fom, int next_state)
Definition: op.c:267
Definition: op.h:64
M0_TL_DEFINE(bos, static, struct m0_be_op)
Definition: sm.h:301
M0_INTERNAL void m0_be_op_set_add(struct m0_be_op *parent, struct m0_be_op *child)
Definition: op.c:297
M0_INTERNAL void m0_sm_group_lock(struct m0_sm_group *grp)
Definition: sm.c:83
static void be_op_state_change(struct m0_be_op *op, enum m0_be_op_state state)
Definition: op.c:163
#define M0_ASSERT_INFO(cond, fmt,...)
M0_INTERNAL bool m0_be_op_is_locked(const struct m0_be_op *op)
Definition: op.c:125
void m0_fom_phase_set(struct m0_fom *fom, int phase)
Definition: fom.c:1688
Definition: op.h:59
Definition: op.h:74
#define M0_PRE_EX(cond)
Definition: op.h:57
uint32_t sm_state
Definition: sm.h:307
struct m0_sm bo_sm
Definition: op.h:75
int32_t rc
Definition: trigger_fop.h:47
M0_INTERNAL void m0_be_op_lock(struct m0_be_op *op)
Definition: op.c:115
#define ARRAY_SIZE(a)
Definition: misc.h:45
M0_INTERNAL bool m0_sm_group_is_locked(const struct m0_sm_group *grp)
Definition: sm.c:107
M0_INTERNAL bool m0_be_op_is_done(struct m0_be_op *op)
Definition: op.c:234
#define M0_IMPOSSIBLE(fmt,...)
M0_INTERNAL void m0_sm_fini(struct m0_sm *mach)
Definition: sm.c:331