Motr  M0
diter.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2015-2020 Seagate Technology LLC and/or its Affiliates
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * For any questions about this software or licensing,
18  * please email opensource@seagate.com or cortx-questions@seagate.com.
19  *
20  */
21 
22 
23 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_CONF
24 #include "lib/trace.h"
25 
26 #include "conf/diter.h"
27 #include "conf/obj_ops.h" /* M0_CONF_DIRNEXT */
28 #include "lib/memory.h"
29 #include "lib/errno.h"
30 
179 
189 };
190 
191 static bool diter_lvl_invariant(const struct m0_conf_diter_lvl *l)
192 {
193  return _0C(l->dl_di != NULL) && _0C(m0_fid_is_set(&l->dl_rel_fid)) &&
194  _0C(M0_IN(l->dl_mode, (M0_DLM_DIR, M0_DLM_ENTRY))) &&
195  _0C(l->dl_lvl < l->dl_di->di_nr_lvls);
196 }
197 
198 static bool diter_invariant(const struct m0_conf_diter *it)
199 {
200  return _0C(it != NULL) && _0C(it->di_confc != NULL) &&
201  _0C(it->di_origin != NULL) && _0C(it->di_nr_lvls != 0) &&
202  _0C(it->di_lvls != NULL) &&
203  _0C(m0_forall(i, it->di_nr_lvls,
204  diter_lvl_invariant(&it->di_lvls[i]))) &&
205  _0C(M0_IN(it->di_phase,
207  _0C(it->di_nr_lvls != 0);
208 }
209 
210 M0_INTERNAL void m0_conf_diter_lvl_init(struct m0_conf_diter_lvl *l,
211  struct m0_conf_diter *it,
212  struct m0_confc *confc, uint32_t lvl,
213  const struct m0_fid *path)
214 {
215  *l = (struct m0_conf_diter_lvl){.dl_di = it,
216  .dl_rel_fid = *path,
217  .dl_lvl = lvl};
218 }
219 
221  struct m0_confc_ctx *ctx)
222 {
223  if (it->di_locked)
225  else
227 }
228 
229 M0_INTERNAL void m0_conf_diter_lvl_fini(struct m0_conf_diter_lvl *l)
230 {
231  struct m0_confc_ctx *ctx = &l->dl_cctx[M0_DLM_DIR].lc_ctx;
232  struct m0_conf_obj *dir = l->dl_cctx[M0_DLM_DIR].lc_result;
233  struct m0_conf_obj *entry= l->dl_cctx[M0_DLM_ENTRY].lc_result;
234  if (dir != NULL && dir->co_nrefs > 0)
236  if (entry != NULL && entry->co_nrefs > 0)
237  m0_confc_close(entry);
238  if (ctx->fc_confc != NULL)
239  diter_confc_ctx_fini(l->dl_di, ctx);
240 }
241 
242 static inline struct m0_conf_obj *diter_lvl_dir_obj(struct m0_conf_diter_lvl *l)
243 {
244  return l->dl_cctx[M0_DLM_DIR].lc_result;
245 }
246 
247 static inline struct m0_conf_obj *
249 {
250  return l->dl_cctx[M0_DLM_ENTRY].lc_result;
251 }
252 
253 static inline struct m0_confc_ctx *diter_lvl_ctx(struct m0_conf_diter_lvl *l)
254 {
255  return &l->dl_cctx[l->dl_mode].lc_ctx;
256 }
257 
258 static inline struct m0_conf_diter_lvl *diter_lvl(struct m0_conf_diter *it)
259 {
260  return &it->di_lvls[it->di_lvl];
261 }
262 
263 static inline void diter_lvl_mode_set(struct m0_conf_diter_lvl *l,
264  enum m0_diter_lvl_mode mode)
265 {
266  l->dl_mode = mode;
267 }
268 
269 static bool diter_chan_cb(struct m0_clink *link)
270 {
271  struct m0_conf_diter *it = container_of(link, struct m0_conf_diter,
272  di_clink);
273  struct m0_confc_ctx *ctx = diter_lvl_ctx(&it->di_lvls[it->di_lvl]);
274 
276  m0_chan_signal_lock(&it->di_wait);
277  m0_clink_del(link);
278  }
279  return true;
280 }
281 
282 M0_INTERNAL int m0_conf__diter_init(struct m0_conf_diter *it,
283  struct m0_confc *confc,
284  struct m0_conf_obj *origin,
285  uint32_t nr_lvls,
286  const struct m0_fid *path)
287 {
288  int lvl;
289 
290  M0_ENTRY("it=%p confc=%p origin=" FID_F " nr_lvls=%u path=" FID_F,
291  it, confc, FID_P(&origin->co_id), nr_lvls, FID_P(path));
292  M0_PRE(origin->co_status == M0_CS_READY);
293 
294  *it = (struct m0_conf_diter){ .di_confc = confc,
295  .di_nr_lvls = nr_lvls,
296  .di_origin = origin,
297  .di_phase = DPH_LVL_OPEN};
298 
299  M0_ALLOC_ARR(it->di_lvls, it->di_nr_lvls);
300  if (it->di_lvls == NULL)
301  return M0_ERR(-ENOMEM);
302  for (lvl = 0; lvl < nr_lvls; ++lvl)
303  m0_conf_diter_lvl_init(&it->di_lvls[lvl], it, confc, lvl,
304  &path[lvl]);
305  m0_clink_init(&it->di_clink, diter_chan_cb);
306  m0_mutex_init(&it->di_wait_mutex);
307  m0_chan_init(&it->di_wait, &it->di_wait_mutex);
308 
310  return M0_RC(0);
311 }
312 
313 M0_INTERNAL void m0_conf_diter_fini(struct m0_conf_diter *it)
314 {
315  int lvl;
316 
317  M0_ENTRY();
318 
320 
321  for (lvl = 0; lvl < it->di_nr_lvls; ++lvl)
322  m0_conf_diter_lvl_fini(&it->di_lvls[lvl]);
323  m0_free(it->di_lvls);
324  m0_clink_fini(&it->di_clink);
325  m0_chan_fini_lock(&it->di_wait);
326  m0_mutex_fini(&it->di_wait_mutex);
327 
328  M0_LEAVE();
329 }
330 
331 M0_INTERNAL void m0_conf_diter_locked_set(struct m0_conf_diter *it,
332  bool locked)
333 {
334  it->di_locked = locked;
335 }
336 
337 M0_INTERNAL void m0_conf_diter_wait_arm(struct m0_conf_diter *it,
338  struct m0_clink *clink)
339 {
341 
342  m0_clink_add_lock(&it->di_wait, clink);
343 }
344 
345 static void diter_wait_arm(struct m0_conf_diter *it, struct m0_confc_ctx *ctx)
346 {
347  if (it->di_locked)
348  m0_clink_add(&ctx->fc_mach.sm_chan, &it->di_clink);
349  else
350  m0_clink_add_lock(&ctx->fc_mach.sm_chan, &it->di_clink);
351 }
352 
353 static void diter_wait_cancel(struct m0_clink *clink, bool locked)
354 {
355  if (locked)
357  else
359 }
360 
362  struct m0_conf_obj *result)
363 {
364  l->dl_cctx[l->dl_mode].lc_result = result;
365 }
366 
368 {
369  struct m0_conf_obj *origin = NULL;
370  struct m0_conf_diter_lvl *curr_lvl;
371  struct m0_conf_diter_lvl *prev_lvl;
372 
373  curr_lvl = diter_lvl(it);
374  switch (curr_lvl->dl_mode) {
375  case M0_DLM_DIR:
376  M0_ASSERT(it->di_phase == DPH_LVL_OPEN);
377  if (it->di_lvl == 0 && curr_lvl->dl_nr_open == 1)
378  origin = it->di_origin;
379  else {
380  prev_lvl = &it->di_lvls[it->di_lvl - 1];
381  origin = diter_lvl_entry_obj(prev_lvl);
382  }
383  break;
384  case M0_DLM_ENTRY:
385  M0_ASSERT(it->di_phase == DPH_LVL_READ);
386  origin = diter_lvl_dir_obj(curr_lvl);
387  break;
388  default:
389  M0_IMPOSSIBLE("Invalid level mode");
390  }
391 
392  return origin;
393 }
394 
395 static int diter_wait(struct m0_conf_diter *it)
396 {
397  struct m0_conf_diter_lvl *lvl;
398  struct m0_confc_ctx *ctx;
399  struct m0_conf_obj *prev;
400  int rc;
401 
402  M0_ENTRY();
403 
404  lvl = diter_lvl(it);
405  ctx = diter_lvl_ctx(lvl);
406  prev = diter_lvl_dir_obj(lvl);
407  rc = it->di_locked ? m0_confc_ctx_error(ctx) :
409  if (rc != 0) {
411  return M0_ERR(rc);
412  }
415  if (lvl->dl_mode == M0_DLM_DIR) {
416  if (prev != NULL)
417  m0_confc_close(prev);
418  it->di_phase = DPH_LVL_READ;
419  return M0_RC(0);
420  }
421 
422  /* We go depth first. */
423  it->di_phase = (it->di_lvl < it->di_nr_lvls - 1) ?
425 
426  M0_POST(lvl->dl_mode == M0_DLM_ENTRY);
427  return M0_RC(M0_CONF_DIRNEXT);
428 }
429 
430 static void diter_lvl_check(struct m0_conf_diter *it)
431 {
432  struct m0_conf_diter_lvl *lvl;
433 
434  M0_ENTRY();
435 
436  lvl = diter_lvl(it);
437  if (it->di_lvl < it->di_nr_lvls - 1 && lvl->dl_mode == M0_DLM_ENTRY)
438  M0_CNT_INC(it->di_lvl);
439 
440  M0_LEAVE();
441 }
442 
443 M0_INTERNAL int diter_lvl_open(struct m0_conf_diter *it)
444 {
445  struct m0_confc_ctx *ctx;
446  struct m0_conf_obj *origin;
447  struct m0_conf_diter_lvl *lvl;
448 
449  M0_ENTRY();
450 
452  lvl = diter_lvl(it);
453  M0_CNT_INC(lvl->dl_nr_open);
454  /* Set level mode to M0_DLM_DIR to use appropriate m0_confc_ctx. */
456  ctx = diter_lvl_ctx(lvl);
457  origin = diter_lvl_origin(it);
458  m0_confc_ctx_init(diter_lvl_ctx(lvl), it->di_confc);
460  m0_confc_open(ctx, origin, lvl->dl_rel_fid);
461  it->di_phase = DPH_LVL_WAIT;
462 
463  return M0_RC(M0_CONF_DIRMISS);
464 }
465 
466 static int diter_lvl_read(struct m0_conf_diter *it)
467 {
468  struct m0_confc_ctx *ctx;
469  struct m0_conf_diter_lvl *lvl;
470  struct m0_conf_obj *origin;
471  struct m0_conf_obj *entry = NULL;
472  int rc;
473 
474  M0_ENTRY();
475 
476  lvl = diter_lvl(it);
477  M0_CNT_INC(lvl->dl_nr_read);
478  /* Set level mode to M0_DLM_ENTRY to use appropriate m0_confc_ctx. */
480  ctx = diter_lvl_ctx(lvl);
481  origin = diter_lvl_origin(it);
482  M0_ASSERT(origin != NULL);
483  /*
484  * Fetch previous entry configuration object to continue directory
485  * traversal.
486  */
487  entry = diter_lvl_entry_obj(lvl);
488  m0_confc_ctx_init(ctx, it->di_confc);
489  /* Wait on m0_confc_ctx's sm chan to receive completion event. */
491  rc = m0_confc_readdir(ctx, origin, &entry);
492  if (rc != M0_CONF_DIRMISS)
493  diter_wait_cancel(&it->di_clink, it->di_locked);
494  switch (rc) {
495  case M0_CONF_DIREND:
496  if (it->di_lvl == 0) {
497  rc = M0_RC(-ENODATA);
498  } else {
499  /*
500  * We have read all the configuration objects at the
501  * current level, go back to previous level and read next
502  * configuration object.
503  */
504  M0_CNT_DEC(it->di_lvl);
505  rc = 0;
506  }
508  /* Finalise m0_confc_ctx to re-use next time. */
510  break;
511  case M0_CONF_DIRMISS:
512  diter_lvl_result_set(lvl, entry);
513  it->di_phase = DPH_LVL_WAIT;
514  break;
515  case M0_CONF_DIRNEXT:
516  diter_lvl_result_set(lvl, entry);
518  /* We go depth first. */
519  it->di_phase = (it->di_lvl < it->di_nr_lvls - 1) ?
520  DPH_LVL_OPEN : it->di_phase;
521  break;
522  default:
523  M0_IMPOSSIBLE("Invalid case !!");
524  }
525 
526  M0_POST(ergo(rc > 0, M0_IN(rc, (M0_CONF_DIRNEXT,
527  M0_CONF_DIRMISS))));
528  return M0_RC(rc);
529 }
530 
531 M0_INTERNAL int
533  bool (*filter)(const struct m0_conf_obj *obj))
534 {
535  static int (*dit_action[])(struct m0_conf_diter *it) = {
539  };
540  int rc;
541 
542  M0_ENTRY("iterator level=%u phase=%u", it->di_lvl, it->di_phase);
543 
544  do {
546  rc = dit_action[it->di_phase](it);
547  } while (rc == 0 ||
548  (rc == M0_CONF_DIRNEXT && filter != NULL &&
550 
551  return M0_RC(rc == -ENODATA ? 0 : rc);
552 }
553 
554 M0_INTERNAL int
556  bool (*filter)(const struct m0_conf_obj *obj))
557 {
558  struct m0_clink link;
559  int rc;
560 
561  M0_ENTRY();
562 
563  m0_clink_init(&link, NULL);
564  do {
565  m0_conf_diter_wait_arm(it, &link);
567  if (rc == M0_CONF_DIRMISS)
568  m0_chan_wait(&link);
569  diter_wait_cancel(&link, false);
570  } while (rc == M0_CONF_DIRMISS);
571 
572  return M0_RC(rc);
573 }
574 
575 M0_INTERNAL struct m0_conf_obj *
577 {
578  struct m0_conf_diter_lvl *lvl;
579 
580  M0_ENTRY();
581 
582  lvl = &it->di_lvls[it->di_lvl];
583  M0_ASSERT(lvl->dl_mode == M0_DLM_ENTRY);
584 
585  M0_LEAVE();
586  return diter_lvl_entry_obj(lvl);
587 }
588 
590 #undef M0_TRACE_SUBSYSTEM
struct m0_fid co_id
Definition: obj.h:208
M0_INTERNAL void m0_chan_wait(struct m0_clink *link)
Definition: chan.c:336
#define M0_PRE(cond)
#define M0_ALLOC_ARR(arr, nr)
Definition: memory.h:84
static struct m0_conf_obj * diter_lvl_entry_obj(struct m0_conf_diter_lvl *l)
Definition: diter.c:248
#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
M0_INTERNAL void m0_clink_del(struct m0_clink *link)
Definition: chan.c:267
M0_INTERNAL void m0_clink_del_lock(struct m0_clink *link)
Definition: chan.c:293
m0_diter_lvl_mode
Definition: diter.h:144
#define ergo(a, b)
Definition: misc.h:293
M0_INTERNAL struct m0_conf_obj * m0_confc_ctx_result(struct m0_confc_ctx *ctx)
Definition: confc.c:771
M0_LEAVE()
diter_phase
Definition: diter.c:185
M0_INTERNAL int m0_conf_diter_next_sync(struct m0_conf_diter *it, bool(*filter)(const struct m0_conf_obj *obj))
Definition: diter.c:555
static struct m0_be_emap_cursor it
Definition: extmap.c:46
uint32_t dl_nr_read
Definition: diter.h:188
static int diter_lvl_read(struct m0_conf_diter *it)
Definition: diter.c:466
M0_INTERNAL int32_t m0_confc_ctx_error_lock(const struct m0_confc_ctx *ctx)
Definition: confc.c:765
uint32_t dl_nr_open
Definition: diter.h:183
static int diter_wait(struct m0_conf_diter *it)
Definition: diter.c:395
#define container_of(ptr, type, member)
Definition: misc.h:33
M0_INTERNAL bool m0_fid_is_set(const struct m0_fid *fid)
Definition: fid.c:106
static struct foo * obj
Definition: tlist.c:302
#define m0_confc_open(ctx, origin,...)
Definition: confc.h:678
M0_INTERNAL int diter_lvl_open(struct m0_conf_diter *it)
Definition: diter.c:443
return M0_RC(rc)
#define M0_ENTRY(...)
Definition: trace.h:170
Definition: filter.py:1
int i
Definition: dir.c:1033
uint64_t co_nrefs
Definition: obj.h:231
return M0_ERR(-EOPNOTSUPP)
M0_INTERNAL void m0_confc_ctx_fini(struct m0_confc_ctx *ctx)
Definition: confc.c:716
M0_INTERNAL void m0_chan_init(struct m0_chan *chan, struct m0_mutex *ch_guard)
Definition: chan.c:96
#define M0_ASSERT(cond)
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_confc_ctx_is_completed(const struct m0_confc_ctx *ctx)
Definition: confc.c:742
static void diter_confc_ctx_fini(struct m0_conf_diter *it, struct m0_confc_ctx *ctx)
Definition: diter.c:220
M0_INTERNAL int m0_confc_ctx_init(struct m0_confc_ctx *ctx, struct m0_confc *confc)
Definition: confc.c:643
M0_INTERNAL void m0_conf_diter_wait_arm(struct m0_conf_diter *it, struct m0_clink *clink)
Definition: diter.c:337
static bool diter_invariant(const struct m0_conf_diter *it)
Definition: diter.c:198
M0_INTERNAL void m0_mutex_init(struct m0_mutex *mutex)
Definition: mutex.c:35
#define M0_POST(cond)
static void diter_lvl_mode_set(struct m0_conf_diter_lvl *l, enum m0_diter_lvl_mode mode)
Definition: diter.c:263
static int struct dentry int mode
Definition: dir.c:589
M0_INTERNAL int m0_conf_diter_next(struct m0_conf_diter *it, bool(*filter)(const struct m0_conf_obj *obj))
Definition: diter.c:532
static struct m0_clink clink[RDWR_REQUEST_MAX]
static struct fdmi_ctx ctx
Definition: main.c:80
#define FID_P(f)
Definition: fid.h:77
static bool diter_chan_cb(struct m0_clink *link)
Definition: diter.c:269
static struct m0_clink l[NR]
Definition: chan.c:37
M0_INTERNAL void m0_chan_signal_lock(struct m0_chan *chan)
Definition: chan.c:165
enum m0_diter_lvl_mode dl_mode
Definition: diter.h:179
static struct m0_confc_ctx * diter_lvl_ctx(struct m0_conf_diter_lvl *l)
Definition: diter.c:253
#define m0_forall(var, nr,...)
Definition: misc.h:112
void m0_clink_add_lock(struct m0_chan *chan, struct m0_clink *link)
Definition: chan.c:255
M0_INTERNAL void m0_conf_diter_locked_set(struct m0_conf_diter *it, bool locked)
Definition: diter.c:331
static struct m0_conf_obj * diter_lvl_dir_obj(struct m0_conf_diter_lvl *l)
Definition: diter.c:242
M0_INTERNAL void m0_conf_diter_lvl_fini(struct m0_conf_diter_lvl *l)
Definition: diter.c:229
M0_INTERNAL struct m0_conf_obj * m0_conf_diter_result(const struct m0_conf_diter *it)
Definition: diter.c:576
static void diter_lvl_result_set(struct m0_conf_diter_lvl *l, struct m0_conf_obj *result)
Definition: diter.c:361
#define M0_CNT_INC(cnt)
Definition: arith.h:226
Definition: fid.h:38
M0_INTERNAL void m0_clink_add(struct m0_chan *chan, struct m0_clink *link)
Definition: chan.c:228
M0_INTERNAL void m0_conf_diter_fini(struct m0_conf_diter *it)
Definition: diter.c:313
struct m0_clink di_clink
Definition: diter.h:206
#define _0C(exp)
Definition: assert.h:311
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
enum m0_conf_status co_status
Definition: obj.h:210
static void diter_wait_arm(struct m0_conf_diter *it, struct m0_confc_ctx *ctx)
Definition: diter.c:345
M0_INTERNAL void m0_confc_close(struct m0_conf_obj *obj)
Definition: confc.c:921
#define M0_CNT_DEC(cnt)
Definition: arith.h:219
struct inode * dir
Definition: dir.c:1028
M0_INTERNAL void m0_conf_diter_lvl_init(struct m0_conf_diter_lvl *l, struct m0_conf_diter *it, struct m0_confc *confc, uint32_t lvl, const struct m0_fid *path)
Definition: diter.c:210
Definition: nucleus.c:42
def filter(argv)
Definition: filter.py:27
static bool diter_lvl_invariant(const struct m0_conf_diter_lvl *l)
Definition: diter.c:191
static void diter_lvl_check(struct m0_conf_diter *it)
Definition: diter.c:430
static void diter_wait_cancel(struct m0_clink *clink, bool locked)
Definition: diter.c:353
static struct m0_conf_diter_lvl * diter_lvl(struct m0_conf_diter *it)
Definition: diter.c:258
M0_INTERNAL void m0_chan_fini_lock(struct m0_chan *chan)
Definition: chan.c:112
void m0_free(void *data)
Definition: memory.c:146
M0_INTERNAL int m0_conf__diter_init(struct m0_conf_diter *it, struct m0_confc *confc, struct m0_conf_obj *origin, uint32_t nr_lvls, const struct m0_fid *path)
Definition: diter.c:282
int32_t rc
Definition: trigger_fop.h:47
M0_INTERNAL int32_t m0_confc_ctx_error(const struct m0_confc_ctx *ctx)
Definition: confc.c:759
struct m0_fid dl_rel_fid
Definition: diter.h:172
static struct m0_conf_obj * diter_lvl_origin(struct m0_conf_diter *it)
Definition: diter.c:367
#define FID_F
Definition: fid.h:75
M0_INTERNAL int m0_confc_readdir(struct m0_confc_ctx *ctx, struct m0_conf_obj *dir, struct m0_conf_obj **pptr)
Definition: confc.c:990
#define M0_IMPOSSIBLE(fmt,...)