Motr  M0
plan.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2021 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  * Original author: Andriy Tkachuk <andriy.tkachuk@seagate.com>
21  * Original creation date: 26-Apr-2021
22  */
23 
24 
30 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_LAYOUT
31 #include "lib/trace.h"
32 
33 #include "lib/tlist.h"
34 #include "lib/hash.h"
35 #include "motr/client.h"
36 #include "motr/client_internal.h"
37 #include "motr/io.h" /* m0_op_io */
38 
39 #include "layout/layout.h"
40 #include "layout/plan.h"
41 
42 M0_TL_DESCR_DEFINE(pplops, "plan plops",
43  M0_INTERNAL, struct m0_layout_plop, pl_linkage, pl_magix,
45 M0_TL_DEFINE(pplops, M0_INTERNAL, struct m0_layout_plop);
46 
47 M0_TL_DESCR_DEFINE(pldeps, "plop deps", M0_INTERNAL,
48  struct m0_layout_plop_rel, plr_dep_linkage, plr_magix,
50 M0_TL_DEFINE(pldeps, M0_INTERNAL, struct m0_layout_plop_rel);
51 
52 M0_TL_DESCR_DEFINE(plrdeps, "plop rdeps", M0_INTERNAL,
53  struct m0_layout_plop_rel, plr_rdep_linkage, plr_magix,
55 M0_TL_DEFINE(plrdeps, M0_INTERNAL, struct m0_layout_plop_rel);
56 
66  struct m0_tl lp_plops;
70  struct m0_op *lp_op;
72  struct m0_mutex lp_lock;
73 };
74 
75 static struct m0_layout_plop *
77  struct target_ioreq *ti)
78 {
79  struct m0_layout_plop *plop;
80  struct m0_layout_io_plop *iopl;
81 
83 
84  if (M0_IN(type, (M0_LAT_READ, M0_LAT_WRITE))) {
85  M0_ALLOC_PTR(iopl);
86  plop = iopl == NULL ? NULL : &iopl->iop_base;
87  } else
88  M0_ALLOC_PTR(plop);
89  if (plop == NULL)
90  return NULL;
91 
92  pplops_tlink_init_at(plop, &plan->lp_plops);
93  plop->pl_ti = ti;
94  plop->pl_type = type;
95  plop->pl_plan = plan;
96  plop->pl_state = M0_LPS_INIT;
97  pldeps_tlist_init(&plop->pl_deps);
98  plrdeps_tlist_init(&plop->pl_rdeps);
99 
100  return plop;
101 }
102 
103 static int add_plops_relation(struct m0_layout_plop *rdep,
104  struct m0_layout_plop *dep)
105 {
106  struct m0_layout_plop_rel *plrel;
107 
108  M0_ALLOC_PTR(plrel);
109  if (plrel == NULL)
110  return M0_ERR(-ENOMEM);
111 
112  plrel->plr_dep = dep;
113  plrel->plr_rdep = rdep;
114  pldeps_tlink_init_at_tail(plrel, &rdep->pl_deps);
115  plrdeps_tlink_init_at_tail(plrel, &dep->pl_rdeps);
116 
117  return 0;
118 }
119 
120 static void del_plop_relations(struct m0_layout_plop *plop)
121 {
122  struct m0_layout_plop_rel *rel;
123 
124  m0_tl_teardown(pldeps, &plop->pl_deps, rel) {
125  plrdeps_tlink_del_fini(rel);
126  m0_free(rel);
127  }
128  m0_tl_teardown(plrdeps, &plop->pl_rdeps, rel) {
129  pldeps_tlink_del_fini(rel);
130  m0_free(rel);
131  }
132  pldeps_tlist_fini(&plop->pl_deps);
133  plrdeps_tlist_fini(&plop->pl_rdeps);
134 }
135 
136 M0_INTERNAL struct m0_layout_plan * m0_layout_plan_build(struct m0_op *op)
137 {
138  int rc;
139  struct m0_layout_plan *plan;
140  struct m0_layout_plop *plop;
141  struct m0_layout_plop *plop_out;
142  struct m0_layout_plop *plop_done;
143  struct m0_layout_io_plop *iopl;
144  struct m0_op_common *oc;
145  struct m0_op_obj *oo;
146  struct m0_op_io *ioo;
147  struct m0_layout_instance *linst;
148  struct target_ioreq *ti;
149 
150  M0_ENTRY("op=%p", op);
151 
152  M0_PRE(op != NULL);
153  /* XXX current limitations */
154  M0_PRE(op->op_entity->en_type == M0_ET_OBJ);
155  M0_PRE(M0_IN(op->op_code, (M0_OC_READ, M0_OC_WRITE)));
156 
157  oc = bob_of(op, struct m0_op_common, oc_op, &oc_bobtype);
158  oo = bob_of(oc, struct m0_op_obj, oo_oc, &oo_bobtype);
159  ioo = bob_of(oo, struct m0_op_io, ioo_oo, &ioo_bobtype);
160 
161  linst = oo->oo_layout_instance;
162  M0_ASSERT_INFO(linst != NULL, "layout instance is not initialised, "
163  "was object opened?");
164  M0_ALLOC_PTR(plan);
165  if (plan == NULL) {
166  M0_LOG(M0_ERROR, "failed to allocate memory for the plan");
167  return NULL;
168  }
169 
170  m0_mutex_init(&plan->lp_lock);
171 
172  pplops_tlist_init(&plan->lp_plops);
173  plan->lp_op = op;
174  plan->lp_layout = linst;
175 
176  rc = ioo->ioo_ops->iro_iomaps_prepare(ioo) ?:
178  if (rc != 0)
179  goto out;
180 
181  /*
182  * There is no concurrency at this stage yet, but we take
183  * the lock here because of the check at plop_alloc_init().
184  */
185  m0_mutex_lock(&plan->lp_lock);
186 
187  /* plops are added in LIFO order, so DONE goes 1st. */
188  plop_done = plop_alloc_init(plan, M0_LAT_DONE, NULL);
189  if (plop_done == NULL) {
190  rc = M0_ERR(-ENOMEM);
191  goto out;
192  }
193 
194  m0_htable_for(tioreqht, ti, &ioo->ioo_nwxfer.nxr_tioreqs_hash) {
195  /* Add OUT_READ before READ (LIFO order). */
196  plop_out = plop_alloc_init(plan, M0_LAT_OUT_READ, NULL);
197  rc = add_plops_relation(plop_done, plop_out);
198  if (rc != 0)
199  break;
200 
201  plop = plop_alloc_init(plan, M0_LAT_READ, ti);
202  if (plop == NULL || plop_out == NULL) {
203  rc = M0_ERR(-ENOMEM);
204  break;
205  }
206  plop->pl_ent = ti->ti_fid;
207  iopl = container_of(plop, struct m0_layout_io_plop, iop_base);
208  iopl->iop_ext = ti->ti_ivec;
209  iopl->iop_data = ti->ti_bufvec;
210  iopl->iop_session = ti->ti_session;
211  iopl->iop_goff = ti->ti_goff;
212  rc = add_plops_relation(plop_out, plop);
213  if (rc != 0)
214  break;
216 
217  m0_mutex_unlock(&plan->lp_lock);
218 
219  out:
220  if (rc != 0) {
221  m0_layout_plan_fini(plan);
222  plan = NULL;
223  }
224 
225  M0_LEAVE();
226  return plan;
227 }
228 
229 M0_INTERNAL void m0_layout_plan_fini(struct m0_layout_plan *plan)
230 {
231  struct m0_layout_plop *plop;
232  struct m0_op_common *oc;
233  struct m0_op_obj *oo;
234  struct m0_op_io *ioo;
235  struct target_ioreq *ti;
236 
237  M0_ENTRY("plan=%p", plan);
238 
239  oc = bob_of(plan->lp_op, struct m0_op_common, oc_op, &oc_bobtype);
240  oo = bob_of(oc, struct m0_op_obj, oo_oc, &oo_bobtype);
241  ioo = bob_of(oo, struct m0_op_io, ioo_oo, &ioo_bobtype);
242 
243  /*
244  * There should not be any concurrency by this stage already.
245  * But if there is any (which is a bug) - we want it to be
246  * caught properly with the assert below which checks pl_state.
247  * So we want this check to be atomic with any possible plop
248  * changes going in parallel (which is, again, a logical bug).
249  */
250  m0_mutex_lock(&plan->lp_lock);
251 
252  m0_htable_for(tioreqht, ti, &ioo->ioo_nwxfer.nxr_tioreqs_hash) {
253  tioreqht_htable_del(&ioo->ioo_nwxfer.nxr_tioreqs_hash, ti);
254  target_ioreq_fini(ti);
256 
257  if (ioo->ioo_iomaps != NULL)
258  ioo->ioo_ops->iro_iomaps_destroy(ioo);
259 
260  m0_tl_teardown(pplops, &plan->lp_plops, plop) {
261  if (plop->pl_ops && plop->pl_ops->po_fini)
262  plop->pl_ops->po_fini(plop);
263  /* For each plan_get(), plop_done() must be called. */
264  M0_ASSERT(M0_IN(plop->pl_state, (M0_LPS_INIT, M0_LPS_DONE)));
265  del_plop_relations(plop);
266  m0_free(plop);
267  }
268  pplops_tlist_fini(&plan->lp_plops);
269 
270  m0_mutex_unlock(&plan->lp_lock);
271  m0_mutex_fini(&plan->lp_lock);
272 
273  m0_free(plan);
274 
275  M0_LEAVE();
276 }
277 
278 M0_INTERNAL int m0_layout_plan_get(struct m0_layout_plan *plan, uint64_t colour,
279  struct m0_layout_plop **plop)
280 {
281  M0_PRE(plan != NULL);
282  M0_PRE(plop != NULL);
283  M0_PRE(plan->lp_op != NULL);
284 
285  m0_mutex_lock(&plan->lp_lock);
286 
287  if (plan->lp_last_plop == NULL)
288  *plop = pplops_tlist_head(&plan->lp_plops);
289  else
290  *plop = pplops_tlist_next(&plan->lp_plops, plan->lp_last_plop);
291 
292  plan->lp_last_plop = *plop;
293 
294  m0_mutex_unlock(&plan->lp_lock);
295 
296  return M0_RC(0);
297 }
298 
299 M0_INTERNAL int m0_layout_plop_start(struct m0_layout_plop *plop)
300 {
301  M0_PRE(plop->pl_state == M0_LPS_INIT);
302  /* All the dependencies for this plop must be done. */
303  M0_PRE(m0_tl_forall(pldeps, rel, &plop->pl_deps,
304  rel->plr_dep->pl_state == M0_LPS_DONE));
305 
306  plop->pl_state = M0_LPS_STARTED;
307 
308  return M0_RC(0);
309 }
310 
311 M0_INTERNAL void m0_layout_plop_done(struct m0_layout_plop *plop)
312 {
313  M0_PRE(plop->pl_state == M0_LPS_STARTED);
314  plop->pl_state = M0_LPS_DONE;
315 }
316 
317 #undef M0_TRACE_SUBSYSTEM
318 
321 /*
322  * Local variables:
323  * c-indentation-style: "K&R"
324  * c-basic-offset: 8
325  * tab-width: 8
326  * fill-column: 80
327  * scroll-step: 1
328  * End:
329  */
static void del_plop_relations(struct m0_layout_plop *plop)
Definition: plan.c:120
const struct m0_bob_type oo_bobtype
Definition: client.c:45
#define M0_PRE(cond)
M0_INTERNAL void m0_layout_plop_done(struct m0_layout_plop *plop)
Definition: plan.c:311
M0_INTERNAL void m0_mutex_unlock(struct m0_mutex *mutex)
Definition: mutex.c:66
#define m0_htable_for(name, var, htable)
Definition: hash.h:483
#define NULL
Definition: misc.h:38
const struct m0_layout_plop_ops * pl_ops
Definition: plan.h:408
M0_INTERNAL int m0_layout_plan_get(struct m0_layout_plan *plan, uint64_t colour, struct m0_layout_plop **plop)
Definition: plan.c:278
struct m0_mutex lp_lock
Definition: plan.c:72
#define M0_LOG(level,...)
Definition: trace.h:167
M0_LEAVE()
const struct m0_op_io_ops * ioo_ops
struct m0_tl pl_deps
Definition: plan.h:388
struct m0_indexvec_varr ti_bufvec
struct m0_fid pl_ent
Definition: plan.h:398
struct m0_layout_instance * lp_layout
Definition: plan.c:64
#define container_of(ptr, type, member)
Definition: misc.h:33
M0_INTERNAL void m0_mutex_lock(struct m0_mutex *mutex)
Definition: mutex.c:49
struct m0_op * lp_op
Definition: plan.c:70
M0_TL_DESCR_DEFINE(pplops, "plan plops", M0_INTERNAL, struct m0_layout_plop, pl_linkage, pl_magix, M0_LAYOUT_PLAN_PLOP_MAGIC, M0_LAYOUT_PPLOPS_HMAGIC)
enum m0_layout_plop_state pl_state
Definition: plan.h:359
return M0_RC(rc)
op
Definition: libdemo.c:64
#define M0_ENTRY(...)
Definition: trace.h:170
const struct m0_bob_type ioo_bobtype
Definition: io_req.c:153
Definition: client.h:641
struct nw_xfer_request ioo_nwxfer
int(* nxo_distribute)(struct nw_xfer_request *xfer)
const struct m0_bob_type oc_bobtype
Definition: client.c:44
return M0_ERR(-EOPNOTSUPP)
struct m0_bufvec iop_data
Definition: plan.h:499
struct m0_tl lp_plops
Definition: plan.c:66
#define m0_tl_teardown(name, head, obj)
Definition: tlist.h:708
#define M0_ASSERT(cond)
m0_bindex_t iop_goff
Definition: plan.h:489
M0_INTERNAL bool m0_mutex_is_locked(const struct m0_mutex *mutex)
Definition: mutex.c:95
const struct nw_xfer_ops * nxr_ops
M0_TL_DEFINE(pplops, M0_INTERNAL, struct m0_layout_plop)
enum m0_layout_plop_type pl_type
Definition: plan.h:357
Definition: tlist.h:251
#define bob_of(ptr, type, field, bt)
Definition: bob.h:140
M0_INTERNAL int m0_layout_plop_start(struct m0_layout_plop *plop)
Definition: plan.c:299
struct target_ioreq * pl_ti
Definition: plan.h:363
struct m0_tl pl_rdeps
Definition: plan.h:393
M0_INTERNAL void m0_mutex_init(struct m0_mutex *mutex)
Definition: mutex.c:35
void(* iro_iomaps_destroy)(struct m0_op_io *ioo)
Definition: pg.h:574
struct m0_htable nxr_tioreqs_hash
struct m0_layout_plop * plr_rdep
Definition: plan.h:418
static void target_ioreq_fini(struct target_ioreq *ti)
Definition: file.c:4708
static struct m0_layout_plop * plop_alloc_init(struct m0_layout_plan *plan, enum m0_layout_plop_type type, struct target_ioreq *ti)
Definition: plan.c:76
struct m0_rpc_session * ti_session
struct m0_layout_plan * pl_plan
Definition: plan.h:361
struct m0_layout_plop iop_base
Definition: plan.h:479
struct m0_rpc_session * iop_session
Definition: plan.h:482
struct m0_indexvec iop_ext
Definition: plan.h:486
M0_INTERNAL void m0_layout_plan_fini(struct m0_layout_plan *plan)
Definition: plan.c:229
m0_layout_plop_type
Definition: plan.h:249
struct m0_fid ti_fid
#define M0_ALLOC_PTR(ptr)
Definition: memory.h:86
m0_bindex_t ti_goff
Definition: pg.h:785
static int add_plops_relation(struct m0_layout_plop *rdep, struct m0_layout_plop *dep)
Definition: plan.c:103
M0_INTERNAL void m0_mutex_fini(struct m0_mutex *mutex)
Definition: mutex.c:42
int(* iro_iomaps_prepare)(struct m0_op_io *ioo)
Definition: pg.h:567
M0_INTERNAL struct m0_layout_plan * m0_layout_plan_build(struct m0_op *op)
Definition: plan.c:136
void(* po_fini)(struct m0_layout_plop *plop)
Definition: plan.h:449
#define M0_ASSERT_INFO(cond, fmt,...)
struct m0_layout_plop * lp_last_plop
Definition: plan.c:68
#define out(...)
Definition: gen.c:41
int type
Definition: dir.c:1031
struct m0_layout_instance * oo_layout_instance
struct m0_layout_plop * plr_dep
Definition: plan.h:416
void m0_free(void *data)
Definition: memory.c:146
Definition: mutex.h:47
#define m0_htable_endfor
Definition: hash.h:491
int32_t rc
Definition: trigger_fop.h:47
struct m0_indexvec ti_ivec
Definition: pg.h:793
struct pargrp_iomap ** ioo_iomaps
#define m0_tl_forall(name, var, head,...)
Definition: tlist.h:735