Motr  M0
list.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/list.h"
27 
28 #include "be/tx_credit.h" /* m0_be_tx_credit */
29 #include "be/tx.h" /* M0_BE_TX_CAPTURE_PTR */
30 
31 #include "lib/string.h" /* strlen */
32 
39 enum {
41 };
42 
43 static bool be_list_invariant(const struct m0_be_list *blist,
44  const struct m0_be_list_descr *descr)
45 {
46  return _0C(equi(blist->bl_head.blh_head == (void *)&blist->bl_head,
47  blist->bl_head.blh_tail == (void *)&blist->bl_head));
48 }
49 
50 static bool be_tlink_invariant(const struct m0_be_list_link *link,
51  const struct m0_be_list_descr *descr)
52 {
53  return _0C(equi(link->bll_next == link, link->bll_prev == link));
54 }
55 
56 M0_INTERNAL void m0_be_list_credit(enum m0_be_list_op optype,
58  struct m0_be_tx_credit *accum)
59 {
60  struct m0_be_tx_credit cred = {};
61  struct m0_be_tx_credit cred_tlink;
62  struct m0_be_tx_credit cred_tlink_magic;
63  struct m0_be_tx_credit cred_list;
64 
65  cred_tlink = M0_BE_TX_CREDIT_TYPE(struct m0_be_list_link);
66  cred_tlink_magic = M0_BE_TX_CREDIT_TYPE(uint64_t);
67  cred_list = M0_BE_TX_CREDIT_TYPE(struct m0_be_list);
68 
69  switch (optype) {
70  case M0_BLO_CREATE:
71  case M0_BLO_DESTROY:
72  m0_be_tx_credit_add(&cred, &cred_list);
73  break;
74  case M0_BLO_ADD:
75  case M0_BLO_DEL:
76  /* list header */
77  m0_be_tx_credit_add(&cred, &cred_list);
78  /* left list link */
79  m0_be_tx_credit_add(&cred, &cred_tlink);
80  /* right list link */
81  m0_be_tx_credit_add(&cred, &cred_tlink);
82  /* added/deleted element */
83  m0_be_tx_credit_add(&cred, &cred_tlink);
84  break;
87  m0_be_tx_credit_add(&cred, &cred_tlink);
88  m0_be_tx_credit_add(&cred, &cred_tlink_magic);
89  break;
90  default:
91  M0_IMPOSSIBLE("");
92  };
93 
94  m0_be_tx_credit_mul(&cred, nr);
95  m0_be_tx_credit_add(accum, &cred);
96 }
97 
98 /* -------------------------------------------------------------------------
99  * Construction/Destruction:
100  * ------------------------------------------------------------------------- */
101 
102 static void be_list_capture(struct m0_be_list *blist,
103  struct m0_be_tx *tx)
104 {
106  M0_BE_TX_CAPTURE_PTR(NULL, tx, blist);
107 }
108 
109 static void be_tlink_capture(struct m0_be_list_link *link,
110  struct m0_be_tx *tx)
111 {
112  M0_BE_TX_CAPTURE_PTR(NULL, tx, link);
113 }
114 
115 static struct m0_be_list_link *
116 be_list_obj2link(const void *obj,
117  const struct m0_be_list_descr *descr)
118 {
120  (uint64_t)descr->bld_link_offset));
121 
122  return (struct m0_be_list_link *)((char *)obj + descr->bld_link_offset);
123 }
124 
125 static void *be_list_link2obj(struct m0_be_list_link *link,
126  const struct m0_be_list_descr *descr)
127 {
128  M0_PRE((uint64_t)link - (uint64_t)descr->bld_link_offset <
129  (uint64_t)link);
130 
131  return (char *)link - descr->bld_link_offset;
132 }
133 
134 M0_INTERNAL void m0_be_list_create(struct m0_be_list *blist,
135  const struct m0_be_list_descr *descr,
136  struct m0_be_tx *tx)
137 {
138  /* XXX get */
139 
141  .ot_version = M0_BE_LIST_FORMAT_VERSION,
142  .ot_type = M0_FORMAT_TYPE_BE_LIST,
143  .ot_footer_offset = offsetof(struct m0_be_list, bl_format_footer)
144  });
145 
146  blist->bl_magic = descr->bld_head_magic;
147  blist->bl_head.blh_head = (struct m0_be_list_link *)&blist->bl_head;
148  blist->bl_head.blh_tail = (struct m0_be_list_link *)&blist->bl_head;
149 
150  be_list_capture(blist, tx);
151  M0_POST(be_list_invariant(blist, descr));
152 
153  /* XXX put */
154 }
155 
156 M0_INTERNAL void m0_be_list_destroy(struct m0_be_list *blist,
157  const struct m0_be_list_descr *descr,
158  struct m0_be_tx *tx)
159 {
160  /* XXX get */
161 
162  M0_PRE(be_list_invariant(blist, descr));
163  M0_PRE(m0_be_list_is_empty(blist, descr));
164 
165  memset(blist, BE_LIST_POISON_BYTE, sizeof *blist);
166  M0_BE_TX_CAPTURE_PTR(NULL, tx, blist);
167 
168  /* XXX put */
169 }
170 
171 M0_INTERNAL bool m0_be_list_is_empty(struct m0_be_list *blist,
172  const struct m0_be_list_descr *descr)
173 {
174  bool result;
175 
176  /* XXX get */
177 
178  result = blist->bl_head.blh_head == (void *)&blist->bl_head;
179 
180  /* XXX put */
181 
182  return result;
183 }
184 
185 M0_INTERNAL void m0_be_tlink_create(void *obj,
186  const struct m0_be_list_descr *descr,
187  struct m0_be_tx *tx)
188 {
189  struct m0_be_list_link *link = be_list_obj2link(obj, descr);
190 
191  /* XXX get link */
192 
193  link->bll_next = link;
194  link->bll_prev = link;
195  be_tlink_capture(link, tx);
196 
197  /* XXX put link */
198 }
199 
200 M0_INTERNAL void m0_be_tlink_destroy(void *obj,
201  const struct m0_be_list_descr *descr,
202  struct m0_be_tx *tx)
203 {
204  struct m0_be_list_link *link = be_list_obj2link(obj, descr);
205 
206  /* XXX get link */
207 
208  memset(link, BE_LIST_POISON_BYTE, sizeof *link);
209  be_tlink_capture(link, tx);
210 
211  /* XXX put link */
212 }
213 
214 /* -------------------------------------------------------------------------
215  * Iteration interfaces:
216  * ------------------------------------------------------------------------- */
217 
218 static bool be_tlink_is_tail(struct m0_be_list *blist,
219  struct m0_be_list_link *link)
220 {
221  return link->bll_next == (void *)&blist->bl_head;
222 }
223 
224 static bool be_tlink_is_head(struct m0_be_list *blist,
225  struct m0_be_list_link *link)
226 {
227  return link->bll_prev == (void *)&blist->bl_head;
228 }
229 
230 static bool be_tlink_is_in_list(struct m0_be_list_link *link)
231 {
232  return link->bll_prev != link;
233 }
234 
235 M0_INTERNAL void *m0_be_list_tail(struct m0_be_list *blist,
236  const struct m0_be_list_descr *descr)
237 {
238  void *result;
239 
240  /* XXX get */
241 
242  M0_PRE(be_list_invariant(blist, descr));
243 
244  if (m0_be_list_is_empty(blist, descr))
245  result = NULL;
246  else {
247  /*
248  * We don't have to get reference to the blh_tail in current
249  * implementation, because the pointer is not dereferenced.
250  */
251  result = be_list_link2obj(blist->bl_head.blh_tail, descr);
252  }
253 
254  /* XXX put */
255 
256  return result;
257 }
258 
259 M0_INTERNAL void *m0_be_list_head(struct m0_be_list *blist,
260  const struct m0_be_list_descr *descr)
261 {
262  void *result;
263 
264  /* XXX get */
265 
266  M0_PRE(be_list_invariant(blist, descr));
267 
268  if (m0_be_list_is_empty(blist, descr))
269  result = NULL;
270  else
271  result = be_list_link2obj(blist->bl_head.blh_head, descr);
272 
273  /* XXX put */
274 
275  return result;
276 }
277 
278 M0_INTERNAL void *m0_be_list_prev(struct m0_be_list *blist,
279  const struct m0_be_list_descr *descr,
280  const void *obj)
281 {
282  struct m0_be_list_link *link = be_list_obj2link(obj, descr);
283  void *result;
284 
285  /* XXX get */
286  /* XXX get link */
287 
288  M0_PRE(be_list_invariant(blist, descr));
289  if (be_tlink_is_head(blist, link))
290  result = NULL;
291  else
292  result = be_list_link2obj(link->bll_prev, descr);
293 
294  /* XXX put link */
295  /* XXX put */
296 
297  return result;
298 }
299 
300 M0_INTERNAL void *m0_be_list_next(struct m0_be_list *blist,
301  const struct m0_be_list_descr *descr,
302  const void *obj)
303 {
304  struct m0_be_list_link *link = be_list_obj2link(obj, descr);
305  void *result;
306 
307  /* XXX get */
308  /* XXX get link */
309 
310  M0_PRE(be_list_invariant(blist, descr));
311  if (be_tlink_is_tail(blist, link))
312  result = NULL;
313  else
314  result = be_list_link2obj(link->bll_next, descr);
315 
316  /* XXX put link */
317  /* XXX put */
318 
319  return result;
320 }
321 
322 /* -------------------------------------------------------------------------
323  * Modification interfaces:
324  * ------------------------------------------------------------------------- */
325 
326 M0_INTERNAL void m0_be_list_add(struct m0_be_list *blist,
327  const struct m0_be_list_descr *descr,
328  struct m0_be_tx *tx,
329  void *obj)
330 {
331  struct m0_be_list_link *link = be_list_obj2link(obj, descr);
332  struct m0_be_list_link *tmp;
333 
334  /* XXX get */
335  /* XXX get link */
336 
337  M0_PRE(be_list_invariant(blist, descr));
338  M0_PRE(be_tlink_invariant(link, descr));
339  M0_PRE(!be_tlink_is_in_list(link));
340 
341  if (m0_be_list_is_empty(blist, descr)) {
342  blist->bl_head.blh_tail = link;
343  } else {
344  tmp = blist->bl_head.blh_head;
345  /* XXX get tmp */
346  tmp->bll_prev = link;
347  be_tlink_capture(tmp, tx);
348  /* XXX put tmp */
349  }
350  link->bll_prev = (struct m0_be_list_link *)&blist->bl_head;
351  link->bll_next = blist->bl_head.blh_head;
352  blist->bl_head.blh_head = link;
353 
354  be_list_capture(blist, tx);
355  be_tlink_capture(link, tx);
356 
357  M0_POST(be_list_invariant(blist, descr));
358 
359  /* XXX put link */
360  /* XXX put */
361 }
362 
363 M0_INTERNAL void m0_be_list_add_after(struct m0_be_list *blist,
364  const struct m0_be_list_descr *descr,
365  struct m0_be_tx *tx,
366  void *obj,
367  void *obj_new)
368 {
369  struct m0_be_list_link *link = be_list_obj2link(obj_new, descr);
370  struct m0_be_list_link *link_after = be_list_obj2link(obj, descr);
371  struct m0_be_list_link *tmp;
372 
373  /* XXX get */
374  /* XXX get link */
375  /* XXX get link_after */
376 
377  M0_PRE(be_list_invariant(blist, descr));
378  M0_PRE(be_tlink_invariant(link, descr));
379  M0_PRE(be_tlink_invariant(link_after, descr));
380  M0_PRE(!be_tlink_is_in_list(link));
381  M0_PRE(be_tlink_is_in_list(link_after));
382 
383  if (be_tlink_is_tail(blist, link_after)) {
384  blist->bl_head.blh_tail = link;
385  be_list_capture(blist, tx);
386  } else {
387  tmp = link_after->bll_next;
388  /* XXX get tmp */
389  tmp->bll_prev = link;
390  be_tlink_capture(tmp, tx);
391  /* XXX put tmp */
392  }
393  link->bll_prev = link_after;
394  link->bll_next = link_after->bll_next;
395  link_after->bll_next = link;
396 
397  be_tlink_capture(link, tx);
398  be_tlink_capture(link_after, tx);
399 
400  M0_POST(be_list_invariant(blist, descr));
401 
402  /* XXX put link_after */
403  /* XXX put link */
404  /* XXX put */
405 }
406 
407 M0_INTERNAL void m0_be_list_add_before(struct m0_be_list *blist,
408  const struct m0_be_list_descr *descr,
409  struct m0_be_tx *tx,
410  void *obj,
411  void *obj_new)
412 {
413  struct m0_be_list_link *link = be_list_obj2link(obj_new, descr);
414  struct m0_be_list_link *link_before = be_list_obj2link(obj, descr);
415  struct m0_be_list_link *tmp;
416 
417  /* XXX get */
418  /* XXX get link */
419  /* XXX get link_before */
420 
421  M0_PRE(be_list_invariant(blist, descr));
422  M0_PRE(be_tlink_invariant(link, descr));
423  M0_PRE(be_tlink_invariant(link_before, descr));
424  M0_PRE(!be_tlink_is_in_list(link));
425  M0_PRE(be_tlink_is_in_list(link_before));
426 
427  if (be_tlink_is_head(blist, link_before)) {
428  blist->bl_head.blh_head = link;
429  be_list_capture(blist, tx);
430  } else {
431  tmp = link_before->bll_prev;
432  /* XXX get tmp */
433  tmp->bll_next = link;
434  be_tlink_capture(tmp, tx);
435  /* XXX put tmp */
436  }
437  link->bll_prev = link_before->bll_prev;
438  link->bll_next = link_before;
439  link_before->bll_prev = link;
440 
441  be_tlink_capture(link, tx);
442  be_tlink_capture(link_before, tx);
443 
444  M0_POST(be_list_invariant(blist, descr));
445 
446  /* XXX put link_before */
447  /* XXX put link */
448  /* XXX put */
449 }
450 
451 M0_INTERNAL void m0_be_list_add_tail(struct m0_be_list *blist,
452  const struct m0_be_list_descr *descr,
453  struct m0_be_tx *tx,
454  void *obj)
455 {
456  struct m0_be_list_link *link = be_list_obj2link(obj, descr);
457  struct m0_be_list_link *tmp;
458 
459  /* XXX get */
460  /* XXX get link */
461 
462  M0_PRE(be_list_invariant(blist, descr));
463  M0_PRE(be_tlink_invariant(link, descr));
464  M0_PRE(!be_tlink_is_in_list(link));
465 
466  if (m0_be_list_is_empty(blist, descr)) {
467  blist->bl_head.blh_head = link;
468  } else {
469  tmp = blist->bl_head.blh_tail;
470  /* XXX get tmp */
471  tmp->bll_next = link;
472  be_tlink_capture(tmp, tx);
473  /* XXX put tmp */
474  }
475  link->bll_prev = blist->bl_head.blh_tail;
476  link->bll_next = (struct m0_be_list_link *)&blist->bl_head;
477  blist->bl_head.blh_tail = link;
478 
479  be_list_capture(blist, tx);
480  be_tlink_capture(link, tx);
481 
482  M0_POST(be_list_invariant(blist, descr));
483 
484  /* XXX put link */
485  /* XXX put */
486 }
487 
488 M0_INTERNAL void m0_be_list_del(struct m0_be_list *blist,
489  const struct m0_be_list_descr *descr,
490  struct m0_be_tx *tx,
491  void *obj)
492 {
493  struct m0_be_list_link *link = be_list_obj2link(obj, descr);
494  struct m0_be_list_link *tmp;
495  bool head_is_dirty = false;
496 
497 
498  /* XXX get */
499  /* XXX get link */
500 
501  M0_PRE(be_list_invariant(blist, descr));
502  M0_PRE(be_tlink_invariant(link, descr));
504 
505  if (be_tlink_is_head(blist, link)) {
506  blist->bl_head.blh_head = link->bll_next;
507  head_is_dirty = true;
508  } else {
509  tmp = link->bll_prev;
510  /* XXX get tmp */
511  tmp->bll_next = link->bll_next;
512  be_tlink_capture(tmp, tx);
513  /* XXX put tmp */
514  }
515 
516  if (be_tlink_is_tail(blist, link)) {
517  blist->bl_head.blh_tail = link->bll_prev;
518  head_is_dirty = true;
519  } else {
520  tmp = link->bll_next;
521  /* XXX get tmp */
522  tmp->bll_prev = link->bll_prev;
523  be_tlink_capture(tmp, tx);
524  /* XXX put tmp */
525  }
526 
527  if (head_is_dirty)
528  be_list_capture(blist, tx);
529 
530  link->bll_prev = link;
531  link->bll_next = link;
532  be_tlink_capture(link, tx);
533 
534  M0_POST(be_list_invariant(blist, descr));
535 
536  /* XXX put link */
537  /* XXX put */
538 }
539 
541 #undef M0_TRACE_SUBSYSTEM
542 
543 /*
544  * Local variables:
545  * c-indentation-style: "K&R"
546  * c-basic-offset: 8
547  * tab-width: 8
548  * fill-column: 80
549  * scroll-step: 1
550  * End:
551  */
552 /*
553  * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap
554  */
static size_t nr
Definition: dump.c:1505
static void * be_list_link2obj(struct m0_be_list_link *link, const struct m0_be_list_descr *descr)
Definition: list.c:125
#define M0_PRE(cond)
M0_INTERNAL void m0_format_header_pack(struct m0_format_header *dest, const struct m0_format_tag *src)
Definition: format.c:40
#define NULL
Definition: misc.h:38
m0_be_list_op
Definition: list.h:84
M0_INTERNAL void * m0_be_list_tail(struct m0_be_list *blist, const struct m0_be_list_descr *descr)
Definition: list.c:235
M0_INTERNAL void m0_be_list_del(struct m0_be_list *blist, const struct m0_be_list_descr *descr, struct m0_be_tx *tx, void *obj)
Definition: list.c:488
static bool be_tlink_is_in_list(struct m0_be_list_link *link)
Definition: list.c:230
M0_INTERNAL void * m0_be_list_head(struct m0_be_list *blist, const struct m0_be_list_descr *descr)
Definition: list.c:259
static bool be_tlink_invariant(const struct m0_be_list_link *link, const struct m0_be_list_descr *descr)
Definition: list.c:50
uint64_t bld_head_magic
Definition: list.h:62
static bool m0_addu64_will_overflow(uint64_t a, uint64_t b)
Definition: arith.h:235
#define M0_BE_TX_CAPTURE_PTR(seg, tx, ptr)
Definition: tx.h:505
uint64_t m0_bcount_t
Definition: types.h:77
M0_INTERNAL void m0_be_list_create(struct m0_be_list *blist, const struct m0_be_list_descr *descr, struct m0_be_tx *tx)
Definition: list.c:134
M0_INTERNAL void m0_be_list_add(struct m0_be_list *blist, const struct m0_be_list_descr *descr, struct m0_be_tx *tx, void *obj)
Definition: list.c:326
M0_INTERNAL void * m0_be_list_next(struct m0_be_list *blist, const struct m0_be_list_descr *descr, const void *obj)
Definition: list.c:300
#define M0_BE_TX_CREDIT_TYPE(type)
Definition: tx_credit.h:97
static bool be_list_invariant(const struct m0_be_list *blist, const struct m0_be_list_descr *descr)
Definition: list.c:43
static struct foo * obj
Definition: tlist.c:302
static bool be_tlink_is_head(struct m0_be_list *blist, struct m0_be_list_link *link)
Definition: list.c:224
#define equi(a, b)
Definition: misc.h:297
uint64_t bl_magic
Definition: list.h:79
M0_INTERNAL void m0_be_list_add_tail(struct m0_be_list *blist, const struct m0_be_list_descr *descr, struct m0_be_tx *tx, void *obj)
Definition: list.c:451
M0_INTERNAL void m0_be_tlink_create(void *obj, const struct m0_be_list_descr *descr, struct m0_be_tx *tx)
Definition: list.c:185
static struct m0_be_list_link * be_list_obj2link(const void *obj, const struct m0_be_list_descr *descr)
Definition: list.c:116
M0_INTERNAL void m0_be_tx_credit_mul(struct m0_be_tx_credit *c, m0_bcount_t k)
Definition: tx_credit.c:73
M0_INTERNAL void m0_be_tx_credit_add(struct m0_be_tx_credit *c0, const struct m0_be_tx_credit *c1)
Definition: tx_credit.c:44
M0_INTERNAL void * m0_be_list_prev(struct m0_be_list *blist, const struct m0_be_list_descr *descr, const void *obj)
Definition: list.c:278
#define M0_POST(cond)
static void be_list_capture(struct m0_be_list *blist, struct m0_be_tx *tx)
Definition: list.c:102
M0_INTERNAL void m0_be_list_add_before(struct m0_be_list *blist, const struct m0_be_list_descr *descr, struct m0_be_tx *tx, void *obj, void *obj_new)
Definition: list.c:407
M0_INTERNAL void m0_be_tlink_destroy(void *obj, const struct m0_be_list_descr *descr, struct m0_be_tx *tx)
Definition: list.c:200
int bld_link_offset
Definition: list.h:59
M0_INTERNAL void m0_format_footer_update(const void *buffer)
Definition: format.c:95
M0_INTERNAL void m0_be_list_add_after(struct m0_be_list *blist, const struct m0_be_list_descr *descr, struct m0_be_tx *tx, void *obj, void *obj_new)
Definition: list.c:363
static void be_tlink_capture(struct m0_be_list_link *link, struct m0_be_tx *tx)
Definition: list.c:109
struct m0_be_list_link * blh_head
Definition: list.h:72
#define _0C(exp)
Definition: assert.h:311
M0_INTERNAL bool m0_be_list_is_empty(struct m0_be_list *blist, const struct m0_be_list_descr *descr)
Definition: list.c:171
struct m0_format_header bl_format_header
Definition: list.h:77
struct m0_be_list_link * blh_tail
Definition: list.h:73
struct m0_be_list_head bl_head
Definition: list.h:78
static bool be_tlink_is_tail(struct m0_be_list *blist, struct m0_be_list_link *link)
Definition: list.c:218
M0_INTERNAL void m0_be_list_credit(enum m0_be_list_op optype, m0_bcount_t nr, struct m0_be_tx_credit *accum)
Definition: list.c:56
M0_INTERNAL void m0_be_list_destroy(struct m0_be_list *blist, const struct m0_be_list_descr *descr, struct m0_be_tx *tx)
Definition: list.c:156
Definition: tx.h:280
#define M0_IMPOSSIBLE(fmt,...)