Motr  M0
io_pargrp.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2020-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  */
21 
22 #include "motr/client.h"
23 #include "motr/client_internal.h"
24 #include "motr/addb.h"
25 #include "motr/pg.h"
26 #include "motr/io.h"
27 
28 #include "lib/buf.h" /* M0_BUF_INIT_PTR */
29 #include "lib/memory.h" /* m0_alloc, m0_free */
30 #include "lib/errno.h" /* ENOMEM */
31 #include "fid/fid.h" /* m0_fid */
32 #include "rm/rm.h" /* stuct m0_rm_owner */
33 #include "sns/parity_repair.h" /* m0_sns_repair_spare_map*/
34 #include "fd/fd.h" /* m0_fd_fwd_map m0_fd_bwd_map */
35 
36 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_CLIENT
37 #include "lib/trace.h" /* M0_LOG */
38 
56 
59 M0_BOB_DEFINE(M0_INTERNAL, &dtbuf_bobtype, data_buf);
60 
62 const struct m0_bob_type pgiomap_bobtype = {
63  .bt_name = "pargrp_iomap_bobtype",
64  .bt_magix_offset = offsetof(struct pargrp_iomap, pi_magic),
65  .bt_magix = M0_PGROUP_MAGIC,
66  .bt_check = NULL,
67 };
68 
69 const struct m0_bob_type dtbuf_bobtype = {
70  .bt_name = "data_buf_bobtype",
71  .bt_magix_offset = offsetof(struct data_buf, db_magic),
72  .bt_magix = M0_DTBUF_MAGIC,
73  .bt_check = NULL,
74 };
75 
85  const struct m0_op_io *ioo,
86  const struct target_ioreq *tio_req,
87  struct m0_pdclust_src_addr *src)
88 {
89  struct m0_pdclust_tgt_addr tgt;
90  struct m0_pdclust_layout *play;
91 
92  M0_PRE(ioo != NULL);
93  M0_PRE(tio_req != NULL);
94  M0_PRE(src != NULL);
95 
96  play = pdlayout_get(ioo);
97  tgt.ta_obj = tio_req->ti_obj;
100 }
101 
105 M0_INTERNAL uint64_t pargrp_id_find(m0_bindex_t index,
106  const struct m0_op_io *ioo,
107  const struct ioreq_fop *ir_fop)
108 {
109  struct m0_pdclust_src_addr src;
110 
111  pargrp_src_addr(index, ioo, ir_fop->irf_tioreq, &src);
112  return src.sa_group;
113 }
114 
116  struct pargrp_iomap *map,
117  struct m0_pdclust_layout *play,
118  struct m0_pdclust_src_addr *src)
119 {
120  m0_bindex_t goff;
121 
122  M0_PRE(map != NULL);
123  M0_PRE(play != NULL);
124 
125  M0_ENTRY("grpid = %3" PRIu64 ", target_off = %3"PRIu64,
126  map->pi_grpid, toff);
127 
128  goff = map->pi_grpid * data_size(play) +
129  src->sa_unit * layout_unit_size(play) +
130  toff % layout_unit_size(play);
131 
132  M0_LEAVE("global file offset = %3"PRIu64, goff);
133  return goff;
134 }
135 
136 static inline bool is_page_read(struct data_buf *dbuf)
137 {
138  return M0_RC(dbuf->db_flags & PA_READ &&
139  dbuf->db_tioreq != NULL && dbuf->db_tioreq->ti_rc == 0);
140 }
141 
145 M0_INTERNAL bool data_buf_invariant(const struct data_buf *db)
146 {
147  return (db != NULL &&
148  data_buf_bob_check(db) &&
149  ergo(db->db_buf.b_addr != NULL, db->db_buf.b_nob > 0));
150 }
151 
160 static bool data_buf_invariant_nr(const struct pargrp_iomap *map)
161 {
162  uint32_t row;
163  uint32_t col;
164  struct m0_obj *obj;
165  struct m0_pdclust_layout *play;
166 
167  M0_ENTRY();
168 
169  M0_PRE(map != NULL);
170 
171  obj = map->pi_ioo->ioo_obj;
172  play = pdlayout_get(map->pi_ioo);
173 
174  for (row = 0; row < rows_nr(play, obj); ++row) {
175  M0_ASSERT(row < map->pi_max_row);
176  for (col = 0; col < layout_n(play); ++col) {
177  M0_ASSERT(col < map->pi_max_col);
178  if (map->pi_databufs[row][col] != NULL &&
179  !data_buf_invariant(map->pi_databufs[row][col]))
180  return M0_RC(false);
181  }
182  }
183 
184  if (map->pi_paritybufs != NULL) {
185  for (row = 0; row < rows_nr(play, obj); ++row) {
186  M0_ASSERT(row < map->pi_max_row);
187  for (col = 0; col < layout_k(play); ++col) {
188  M0_ASSERT(row < map->pi_max_row);
189  if (map->pi_paritybufs[row][col] != NULL &&
190  !data_buf_invariant(map->pi_paritybufs
191  [row][col]))
192  return M0_RC(false);
193  }
194  }
195  }
196 
197  return M0_RC(true);
198 }
199 
203 M0_INTERNAL bool pargrp_iomap_invariant(const struct pargrp_iomap *map)
204 {
205  M0_ENTRY();
206 
207  if (map == NULL || map->pi_ioo == NULL)
208  return false;
209 
210  return M0_RC(pargrp_iomap_bob_check(map) &&
211  map->pi_ops != NULL &&
212  map->pi_rtype < PIR_NR &&
213  map->pi_databufs != NULL &&
214  map->pi_ioo != NULL &&
215  ergo(m0_vec_count(&map->pi_ivec.iv_vec) > 0 &&
216  map->pi_ivec.iv_vec.v_nr >= 2,
217  m0_forall(i, map->pi_ivec.iv_vec.v_nr - 1,
218  map->pi_ivec.iv_index[i] +
219  map->pi_ivec.iv_vec.v_count[i] <=
220  map->pi_ivec.iv_index[i+1])) &&
222 }
223 
227 M0_INTERNAL bool pargrp_iomap_invariant_nr(const struct m0_op_io *ioo)
228 {
229  M0_ENTRY();
230 
231  M0_PRE(ioo != NULL);
232 
233  return M0_RC(m0_forall(i, ioo->ioo_iomap_nr,
235 }
236 
246 static void data_buf_init(struct data_buf *buf,
247  void *addr,
248  uint64_t addr_size,
249  uint64_t flags)
250 {
251  M0_ENTRY();
252 
253  M0_PRE(buf != NULL);
254  M0_PRE(addr != NULL);
256 
257  data_buf_bob_init(buf);
258  buf->db_flags = flags;
259  m0_buf_init(&buf->db_buf, addr, addr_size);
260  buf->db_tioreq = NULL;
261  buf->db_maj_ele = M0_KEY_VAL_NULL;
262 
263  M0_LEAVE();
264 }
265 
272 static void data_buf_fini(struct data_buf *buf)
273 {
274  M0_ENTRY();
275 
276  M0_PRE(buf != NULL);
277 
278  data_buf_bob_fini(buf);
279  buf->db_flags = PA_NONE;
280 
281  M0_LEAVE();
282 }
283 
290 static void data_buf_dealloc_fini(struct data_buf *buf)
291 {
292  M0_ENTRY("data_buf %p", buf);
293 
295 
296  if ((buf->db_flags & PA_APP_MEMORY) == 0) {
297  m0_free_aligned(buf->db_buf.b_addr,
298  buf->db_buf.b_nob,
299  M0_NETBUF_SHIFT);
300  }
301 
302  if (buf->db_auxbuf.b_addr != NULL) {
303  m0_free_aligned(buf->db_auxbuf.b_addr,
304  buf->db_auxbuf.b_nob,
305  M0_NETBUF_SHIFT);
306  }
307 
309  m0_free(buf);
310 
311  M0_LEAVE();
312 }
313 
323 static struct data_buf *data_buf_alloc_init(struct m0_obj *obj,
324  enum page_attr pattr)
325 {
326  struct m0_client *instance;
327  struct data_buf *buf;
328  void *addr;
329 
330  M0_ENTRY();
331 
332  M0_PRE(obj != NULL);
334  M0_PRE(instance != NULL);
335 
336  addr = m0_alloc_aligned(obj_buffer_size(obj), M0_NETBUF_SHIFT);
337  if (addr == NULL) {
338  M0_LOG(M0_ERROR, "Failed to get free page");
339  return NULL;
340  }
341 
342  M0_ALLOC_PTR(buf);
343  if (buf == NULL) {
345  M0_NETBUF_SHIFT);
346  M0_LOG(M0_ERROR, "Failed to allocate data_buf");
347  return NULL;
348  }
349 
351 
353  M0_LEAVE();
354  return buf;
355 }
356 
358  int row, enum page_attr pattr)
359 {
360  struct data_buf *buf;
361  void *addr;
362  size_t size;
363 
364  M0_ENTRY();
365 
366  M0_ALLOC_PTR(buf);
367  if (buf == NULL) {
368  M0_LOG(M0_ERROR, "Failed to allocate data_buf");
369  return NULL;
370  }
371  /*
372  * Column for data is always zero, as replication implies
373  * N == 1 in pdclust layout.
374  */
375  addr = map->pi_databufs[row][0]->db_buf.b_addr;
376  size = map->pi_databufs[row][0]->db_buf.b_nob;
377  data_buf_init(buf, addr, size, pattr);
378 
380  M0_LEAVE();
381  return buf;
382 }
383 
392 static m0_bindex_t seg_set(struct pargrp_iomap *map, uint32_t seg,
393  struct m0_ivec_cursor *cur, m0_bindex_t grpend)
394 {
395  m0_bindex_t end = m0_ivec_cursor_conti(cur, grpend);
396 
397  INDEX(&map->pi_ivec, seg) = m0_ivec_cursor_index(cur);
398  COUNT(&map->pi_ivec, seg) = end - INDEX(&map->pi_ivec, seg);
399 
400  return end;
401 }
402 
404 static void seg_idx_inc_round(struct pargrp_iomap *map, uint32_t seg,
405  uint64_t sz)
406 {
407  m0_bindex_t idx = m0_round_up(INDEX(&map->pi_ivec, seg) + 1, sz);
408 
409  COUNT(&map->pi_ivec, seg) -= idx - INDEX(&map->pi_ivec, seg);
410  INDEX(&map->pi_ivec, seg) = idx;
411 }
412 
414 static void seg_align(struct pargrp_iomap *map, uint32_t seg,
415  m0_bindex_t end, uint64_t sz)
416 {
417  m0_bindex_t idx = round_down(INDEX(&map->pi_ivec, seg), sz);
418 
419  INDEX(&map->pi_ivec, seg) = idx;
420  COUNT(&map->pi_ivec, seg) = round_up(end, sz) - idx;
421 }
422 
428  struct m0_ivec_cursor *cursor,
429  struct m0_bufvec_cursor *buf_cursor,
430  bool rmw)
431 {
432  int rc;
433  uint32_t seg;
434  m0_bindex_t seg_end = 0;
435  m0_bcount_t grpsize;
436  m0_bcount_t pagesize;
437  m0_bcount_t count = 0;
438  m0_bindex_t grpstart;
439  m0_bindex_t grpend;
440  struct m0_pdclust_layout *play;
441 
442  M0_PRE(map != NULL);
443 
444  play = pdlayout_get(map->pi_ioo);
445  grpsize = data_size(play);
446  grpstart = grpsize * map->pi_grpid;
447  grpend = grpstart + grpsize;
448  pagesize = m0__page_size(map->pi_ioo);
449 
450  for (seg = 0; !m0_ivec_cursor_move(cursor, count) &&
451  m0_ivec_cursor_index(cursor) < grpend;) {
452  /*
453  * Skips the current segment if it is completely spanned by
454  * rounding up/down of an earlier segment.
455  */
456  if (map->pi_ops->pi_spans_seg(map,
457  m0_ivec_cursor_index(cursor),
458  m0_ivec_cursor_step(cursor))) {
459  count = m0_ivec_cursor_step(cursor);
460  continue;
461  }
462 
463  seg_end = seg_set(map, seg, cursor, grpend);
464 
465  /*
466  * If current segment is _partially_ spanned by previous
467  * segment in pargrp_iomap::pi_ivec, start of segment is
468  * rounded up to move to next page.
469  *
470  * FIXME: When indexvec is prepared with segments overlapping
471  * each other and either 1 or multiple segments span the
472  * boundary of the parity group, then the processing of indexvec
473  * fails to map them properly to map->pi_ivec.
474  * EOS-5083 is created to handle this.
475  */
476  if (seg > 0 && INDEX(&map->pi_ivec, seg) <
477  seg_endpos(&map->pi_ivec, seg - 1))
478  seg_idx_inc_round(map, seg, pagesize);
479 
480  ++map->pi_ivec.iv_vec.v_nr;
481 
482  M0_LOG(M0_DEBUG, "[%p] pre grp_id=%" PRIu64 " seg=%"PRIu32
483  " =[%" PRIu64 ",+%" PRIu64 ")", map->pi_ioo, map->pi_grpid,
484  seg, INDEX(&map->pi_ivec, seg),
485  COUNT(&map->pi_ivec, seg));
486 
487  rc = map->pi_ops->pi_seg_process(map, seg, rmw, 0, buf_cursor);
488  if (rc != 0)
489  return M0_ERR(rc);
490 
491  seg_align(map, seg, seg_end, pagesize);
492 
493  M0_LOG(M0_DEBUG, "[%p] post grp_id=%" PRIu64 " seg=%"PRIu32
494  " =[%" PRIu64 ",+%" PRIu64 ")", map->pi_ioo,
495  map->pi_grpid, seg,
496  INDEX(&map->pi_ivec, seg),
497  COUNT(&map->pi_ivec, seg));
498 
499  count = seg_end - m0_ivec_cursor_index(cursor);
500  M0_LOG(M0_DEBUG, "[%p] cursor advance +%" PRIu64 " from %"PRIu64,
501  map->pi_ioo, count, m0_ivec_cursor_index(cursor));
502  ++seg;
503  }
504 
505  return M0_RC(0);
506 }
507 
534  m0_bcount_t data_pages_nr,
535  m0_bcount_t parity_pages_nr)
536 {
537  int rc;
538  /*
539  * In read-old the number of pages to be read is the same as
540  * the number of pages to be written.
541  *
542  * TODO: Can use number of data_buf structures instead of using
543  * indexvec_page_nr().
544  */
545  uint64_t ro_pages_nr = iomap_page_nr(map) + parity_pages_nr;
546  /*
547  * In read-rest the number of pages to be read is all data
548  * pages which are not fully spanned by the io vector.
549  */
550  uint64_t rr_pages_nr = data_pages_nr -
551  map->pi_ops->pi_fullpages_find(map);
552 
553  if (rr_pages_nr < ro_pages_nr || map->pi_trunc_partial) {
554  M0_LOG(M0_DEBUG, "[%p]: RR selected", map->pi_ioo);
555  map->pi_rtype = PIR_READREST;
556  rc = map->pi_ops->pi_readrest(map);
557  if (rc != 0)
558  return M0_ERR(rc);
559  } else {
560  M0_LOG(M0_DEBUG, "[%p]: RO selected", map->pi_ioo);
561  map->pi_rtype = PIR_READOLD;
562  rc = map->pi_ops->pi_readold_auxbuf_alloc(map);
563  }
564 
565  return M0_RC(rc);
566 }
567 
579  struct m0_ivec_cursor *cursor,
580  struct m0_bufvec_cursor *buf_cursor)
581 {
582  int rc;
583  bool rmw = false;
584  m0_bcount_t grpsize;
585  m0_bindex_t grpstart;
586  m0_bindex_t grpend;
587  struct m0_pdclust_layout *play;
588  struct m0_op_io *ioo;
589  struct m0_op *op;
590  struct m0_obj *obj;
591  struct m0_client *instance;
592 
593  M0_PRE(map != NULL);
594 
595  ioo = map->pi_ioo;
596  obj = ioo->ioo_obj;
597  op = &ioo->ioo_oo.oo_oc.oc_op;
599 
600  play = pdlayout_get(ioo);
601  grpsize = data_size(play);
602  grpstart = grpsize * map->pi_grpid;
603  grpend = grpstart + grpsize;
604 
605  /*
606  * For a write, if this map does not span the whole parity group,
607  * it is a read-modify-write.
608  *
609  * In replicated layout (N == 1) we don't do "rmw". Even if the
610  * incoming IO does not span the entire data unit, but spans it
611  * partially (but in quantum of full pages) there is no need to
612  * read parity pages for update. Because they map directly to
613  * the respective data pages anyway (in replicated layout they
614  * are shared to optimise the memory footprint).
615  *
616  * If partial page IO was allowed, reading the older copy (either
617  * of data or parity) would become necessary in order to prepare
618  * the new page in which incoming IO is merged with older values.
619  * But partial page modifications are not currently supported.
620  */
621  if (M0_IN(op->op_code, (M0_OC_FREE, M0_OC_WRITE)) &&
622  (m0_ivec_cursor_index(cursor) > grpstart ||
623  m0_ivec_cursor_conti(cursor, grpend) < grpend) &&
625  rmw = true;
626 
627  M0_ENTRY("[%p] map=%p grp=%" PRIu64 " [%" PRIu64 ",+%" PRIu64 ") rmw=%d",
628  ioo, map, map->pi_grpid, grpstart, grpsize, !!rmw);
629 
630  if (op->op_code == M0_OC_FREE && rmw)
631  map->pi_trunc_partial = true;
632 
633  /* In 'verify mode', read all data units in this parity group */
634  if (op->op_code == M0_OC_READ &&
635  instance->m0c_config->mc_is_read_verify) {
636  /*
637  * Full parity group.
638  * Note: object doesn't have size attribute.
639  */
640  SEG_NR(&map->pi_ivec) = 1;
641  INDEX(&map->pi_ivec, 0) = grpstart;
642  COUNT(&map->pi_ivec, 0) = grpsize;
643 
644  rc = map->pi_ops->pi_seg_process(map, 0, rmw,
645  m0_ivec_cursor_index(cursor),
646  buf_cursor);
647  m0_ivec_cursor_move_to(cursor, grpend);
648  } else
650  buf_cursor, rmw);
651  if (rc != 0)
652  return M0_ERR_INFO(rc, "[%p] failed", ioo);
653 
654  if (rmw) {
656  parity_units_page_nr(play, obj));
657  if (rc != 0)
658  return M0_ERR_INFO(rc, "[%p] failed", ioo);
659  }
660 
661  if (map->pi_ioo->ioo_pbuf_type == M0_PBUF_DIR)
662  rc = map->pi_ops->pi_paritybufs_alloc(map);
663  /*
664  * In case of replicated layout write IO parity buffers
665  * share a pointer with data buffer.
666  */
667  else if (map->pi_ioo->ioo_pbuf_type == M0_PBUF_IND)
668  rc = map->pi_ops->pi_data_replicate(map);
669 
671  return M0_RC(rc);
672 }
673 
686 {
687  uint32_t row;
688  uint32_t col;
689  uint64_t nr = 0;
690  struct m0_pdclust_layout *play;
691  struct m0_obj *obj;
692  struct m0_op_io *ioo;
693 
694  M0_ENTRY("map %p", map);
695 
696  M0_PRE(map != NULL);
697  ioo = map->pi_ioo;
698  obj = ioo->ioo_obj;
700 
701  play = pdlayout_get(ioo);
702 
703  for (row = 0; row < rows_nr(play, obj); ++row) {
704  M0_ASSERT(row <= map->pi_max_row);
705  for (col = 0; col < layout_n(play); ++col) {
706  M0_ASSERT(col <= map->pi_max_col);
707  if (map->pi_databufs[row][col] &&
708  map->pi_databufs[row][col]->db_flags &
710  ++nr;
711  }
712  }
713 
714  M0_LEAVE("%"PRIu64, nr);
715  return nr; /* Not M0_RC, nr is a uint64_t */
716 }
717 
730 {
731  uint32_t seg;
732 
733  M0_ENTRY();
734 
736 
737  for (seg = 0; seg < map->pi_ivec.iv_vec.v_nr; ++seg) {
738  if (index >= INDEX(&map->pi_ivec, seg) &&
739  index + count <= seg_endpos(&map->pi_ivec, seg))
740  return M0_RC(true);
741  }
742  return M0_RC(false);
743 }
744 
756  uint32_t seg, bool rmw,
757  uint64_t skip_buf_index,
758  struct m0_bufvec_cursor *buf_cursor)
759 {
760  int rc;
761  int flags;
762  bool ret;
763  uint32_t row;
764  uint32_t col;
765  uint64_t count = 0;
766  uint64_t pagesize;
768  m0_bindex_t end;
769  struct m0_ivec_cursor cur;
770  struct m0_pdclust_layout *play;
771  struct m0_op_io *ioo;
772  struct m0_obj *obj;
773  struct m0_op *op;
774  m0_bindex_t grp_off;
775 
776  M0_ENTRY("map=%p seg=%"PRIu32", %s", map, seg, rmw ? "rmw" : "aligned");
777 
778  M0_PRE(map != NULL);
779  ioo = map->pi_ioo;
780  op = &ioo->ioo_oo.oo_oc.oc_op;
781  obj = ioo->ioo_obj;
782  play = pdlayout_get(ioo);
783  pagesize = m0__page_size(ioo);
784  grp_off = data_size(play) * map->pi_grpid;
785 
786  m0_ivec_cursor_init(&cur, &map->pi_ivec);
787  ret = m0_ivec_cursor_move_to(&cur, INDEX(&map->pi_ivec, seg));
788  M0_ASSERT(!ret);
789 
790  /* process a page at each iteration */
791  while (!m0_ivec_cursor_move(&cur, count)) {
793  end = min64u(m0_round_up(start + 1, pagesize),
795  count = end - start;
796 
797  flags = 0;
798  if (M0_IN(op->op_code, (M0_OC_WRITE, M0_OC_FREE))) {
799  flags |= PA_WRITE;
800  flags |= count == pagesize ?
802  /*
803  * Even if PA_PARTPAGE_MODIFY flag is set in
804  * this buffer, the auxiliary buffer can not be
805  * allocated until ::pi_rtype is selected.
806  */
807  if (rmw && (flags & PA_PARTPAGE_MODIFY))
808  flags |= PA_READ;
809  } else {
810  /*
811  * For read IO requests, file_aio_read() has already
812  * delimited the index vector to EOF boundary.
813  */
814  flags |= PA_READ;
815  }
816 
817  page_pos_get(map, start, grp_off, &row, &col);
818  M0_ASSERT(col <= map->pi_max_col);
819  M0_ASSERT(row <= map->pi_max_row);
820 
821  if (start < skip_buf_index) {
822  rc = map->pi_ops->pi_databuf_alloc(map, row, col, NULL);
823  } else {
824  /*
825  * When setting with read_verify mode, it requires to
826  * read the whole parity group while client application
827  * may only ask to read fewer units and allocate less
828  * memory so not able to hold the whole parity group.
829  * In this case, client has to allocate the buffers
830  * internally. So set buf_cursor to NULL when the cursor
831  * reaches the end of application's buffer.
832  */
833  if (buf_cursor && m0_bufvec_cursor_move(buf_cursor, 0))
834  buf_cursor = NULL;
835  rc = map->pi_ops->pi_databuf_alloc(map, row, col,
836  buf_cursor);
837  if (rc == 0 && buf_cursor)
838  m0_bufvec_cursor_move(buf_cursor, count);
839  }
840  M0_LOG(M0_DEBUG, "alloc start=%8" PRIu64 " count=%4"PRIu64
841  " grpid=%3" PRIu64 " row=%u col=%u f=0x%x addr=%p",
842  start, count, map->pi_grpid, row, col, flags,
843  map->pi_databufs[row][col] ?
844  map->pi_databufs[row][col]->db_buf.b_addr : NULL);
845  if (rc != 0)
846  goto err;
847 
848  map->pi_databufs[row][col]->db_flags |= flags;
849 
850  }
851 
852  return M0_RC(0);
853 err:
854  for (row = 0; row < rows_nr(play, obj); ++row) {
855  for (col = 0; col < layout_n(play); ++col) {
856  if (map->pi_databufs[row][col] != NULL) {
858  map->pi_databufs[row][col]);
859  map->pi_databufs[row][col] = NULL;
860  }
861  }
862  }
863 
864  return M0_ERR_INFO(rc, "map=%p seg=%"PRIu32 , map, seg);
865 }
866 
878  uint32_t row,
879  uint32_t col,
880  struct m0_bufvec_cursor *data)
881 {
882  struct m0_obj *obj;
883  struct data_buf *buf;
884  uint64_t flags;
885  void *addr = NULL; /* required */
886 
887  M0_ENTRY("row %u col %u", row, col);
888 
889  M0_PRE(map != NULL);
890  M0_PRE(col <= map->pi_max_col);
891  M0_PRE(row <= map->pi_max_row);
892  M0_PRE(map->pi_databufs[row][col] == NULL);
893 
894  obj = map->pi_ioo->ioo_obj;
895 
896  M0_ALLOC_PTR(buf);
897  if (buf == NULL) {
898  M0_LOG(M0_ERROR, "Failed to allocate data_buf");
899  return M0_ERR(-ENOMEM);
900  }
901 
902  if (data)
904 
906  /* Fall back to allocate-copy route */
907  if (!addr_is_network_aligned(addr) || addr == NULL) {
909  M0_NETBUF_SHIFT);
910  flags = PA_NONE;
911  }
912 
915  map->pi_databufs[row][col] = buf;
916 
917  return M0_RC(map->pi_databufs[row][col] == NULL ? -ENOMEM : 0);
918 }
919 
932  uint32_t row,
933  uint32_t col)
934 {
935  uint64_t pagesize;
936 
937  M0_ENTRY();
939  M0_PRE(map->pi_rtype == PIR_READOLD);
940 
941  pagesize = m0__page_size(map->pi_ioo);
942  map->pi_databufs[row][col]->db_auxbuf.b_addr = (void *)
943  m0_alloc_aligned(pagesize, M0_NETBUF_SHIFT);
944 
945  if (map->pi_databufs[row][col]->db_auxbuf.b_addr == NULL)
946  return M0_ERR(-ENOMEM);
947 
948  map->pi_databufs[row][col]->db_auxbuf.b_nob = pagesize;
949 
950  return M0_RC(0);
951 }
952 
963 {
964  int rc = 0;
965  uint64_t start;
966  uint64_t end;
967  uint64_t count = 0;
968  uint32_t row = 0;
969  uint32_t col = 0;
970  struct m0_ivec_cursor cur;
971  m0_bindex_t grp_size;
972  struct m0_pdclust_layout *play;
973  uint64_t pagesize;
974 
975  M0_ENTRY("map %p", map);
976 
978  M0_PRE(map->pi_rtype == PIR_READOLD);
979  play = pdlayout_get(map->pi_ioo);
980  grp_size = data_size(play) * map->pi_grpid;
981  pagesize = m0__page_size(map->pi_ioo);
982  m0_ivec_cursor_init(&cur, &map->pi_ivec);
983 
984  while (!m0_ivec_cursor_move(&cur, count)) {
986  end = min64u(m0_round_up(start + 1, pagesize),
988  count = end - start;
989  page_pos_get(map, start, grp_size, &row, &col);
990 
991  if (map->pi_databufs[row][col] != NULL) {
992  /*
993  * In Readold approach, all valid pages have to
994  * be read regardless of whether they are fully
995  * occupied or partially occupied.
996  * This is needed in order to calculate correct
997  * parity in differential manner.
998  * Also, read flag should be set only for pages
999  * which lie within end-of-file boundary.
1000  */
1001  /*
1002  * XXX: Client doesn't have object size attribute at
1003  * this moment. How to handle an op which writes
1004  * beyond the 'end' of an object (with holes)?
1005  */
1006  /* XXX: just send the write - the ioserver should
1007  * allocate space. It looks like this code is
1008  * switching to rmw if the write extends the file. */
1009  //if (end < inode->i_size ||
1010  // (inode->i_size > 0 &&
1011  // page_id(end - 1) == page_id(inode->i_size - 1)))
1012  // map->pi_databufs[row][col]->db_flags |=
1013  // PA_READ;
1014 
1015  map->pi_databufs[row][col]->db_flags |= PA_READ;
1016 
1017  rc = pargrp_iomap_auxbuf_alloc(map, row, col);
1018  if (rc != 0)
1019  return M0_ERR(rc);
1020  }
1021  }
1022 
1023  return M0_RC(rc);
1024 }
1025 
1085 {
1086  int rc;
1087  uint32_t row = 0;
1088  uint32_t col = 0;
1089  uint32_t seg;
1090  uint32_t seg_nr;
1091  m0_bindex_t grpstart;
1092  m0_bindex_t grpend;
1094  m0_bindex_t end;
1095  m0_bcount_t count = 0;
1096  struct m0_indexvec *ivec;
1097  struct m0_ivec_cursor cur;
1098  struct m0_op_io *ioo;
1099  struct m0_pdclust_layout *play;
1100  uint64_t pagesize;
1101 
1102  M0_ENTRY("map %p", map);
1103 
1105  M0_PRE(map->pi_rtype == PIR_READREST);
1106 
1107  ioo = map->pi_ioo;
1108  play = pdlayout_get(map->pi_ioo);
1109  ivec = &map->pi_ivec;
1110  seg_nr = map->pi_ivec.iv_vec.v_nr;
1111  grpstart = data_size(play) * map->pi_grpid;
1112  grpend = grpstart + data_size(play);
1113  pagesize = m0__page_size(ioo);
1114 
1115  /* Extends first segment to align with start of parity group. */
1116  COUNT(ivec, 0) += (INDEX(ivec, 0) - grpstart);
1117  INDEX(ivec, 0) = grpstart;
1118 
1119  /* Extends last segment to align with end of parity group. */
1120  COUNT(ivec, seg_nr - 1) = grpend - INDEX(ivec, seg_nr - 1);
1121 
1122  /*
1123  * All io extents _not_ spanned by pargrp_iomap::pi_ivec
1124  * need to be included so that _all_ pages from parity group
1125  * are available to do IO.
1126  */
1127  for (seg = 1; seg_nr > 2 && seg <= seg_nr - 2; ++seg) {
1128  if (seg_endpos(ivec, seg) < INDEX(ivec, seg + 1))
1129  COUNT(ivec, seg) += INDEX(ivec, seg + 1) -
1130  seg_endpos(ivec, seg);
1131  }
1132 
1133  m0_ivec_cursor_init(&cur, &map->pi_ivec);
1134 
1135  while (!m0_ivec_cursor_move(&cur, count)) {
1136 
1138  end = min64u(m0_round_up(start + 1, pagesize),
1140  count = end - start;
1141  page_pos_get(map, start, grpstart, &row, &col);
1142 
1143  if (map->pi_databufs[row][col] == NULL) {
1144  rc = pargrp_iomap_databuf_alloc(map, row, col, NULL);
1145  if (rc != 0)
1146  return M0_ERR(rc);
1147 
1148  /* see comments in readold_xxx above */
1149  map->pi_databufs[row][col]->db_flags |= PA_READ;
1150  }
1151  }
1152 
1153  return M0_RC(0);
1154 }
1155 
1164 {
1165  int rc = 0;
1166  uint32_t row;
1167  uint32_t col;
1168  struct m0_buf *dbufs;
1169  struct m0_buf *pbufs;
1170  struct m0_pdclust_layout *play;
1171  struct m0_client *instance;
1172  struct m0_op *op;
1173  struct m0_op_io *ioo;
1174  struct m0_obj *obj;
1175  uint64_t pagesize;
1176 
1177  M0_ENTRY("map = %p", map);
1178 
1180 
1181  ioo = map->pi_ioo;
1183  op = &ioo->ioo_oo.oo_oc.oc_op;
1185  M0_PRE(instance != NULL);
1186  obj = ioo->ioo_obj;
1187  /*XXX (sining): pargrp_iomap_invariant has checked obj != NULL*/
1188  M0_PRE(obj != NULL);
1189 
1190  /* Allocate memory */
1191  play = pdlayout_get(map->pi_ioo);
1192  M0_ALLOC_ARR(dbufs, layout_n(play));
1193  M0_ALLOC_ARR(pbufs, layout_k(play));
1194 
1195  if (dbufs == NULL || pbufs == NULL) {
1196  rc = -ENOMEM;
1197  goto last;
1198  }
1199  pagesize = m0__page_size(ioo);
1200 
1201  if ((op->op_code == M0_OC_WRITE && map->pi_rtype == PIR_NONE)
1202  || map->pi_rtype == PIR_READREST) {
1203  void *zpage;
1204 
1205  zpage = m0_alloc_aligned(1ULL<<obj->ob_attr.oa_bshift,
1206  M0_NETBUF_SHIFT);
1207  if (zpage == 0) {
1208  rc = -ENOMEM;
1209  goto last;
1210  }
1211 
1212  for (row = 0; row < rows_nr(play, ioo->ioo_obj); ++row) {
1213  for (col = 0; col < layout_n(play); ++col)
1214  if (map->pi_databufs[row][col] != NULL) {
1215  dbufs[col] =
1216  map->pi_databufs[row][col]->db_buf;
1217  } else {
1218  dbufs[col].b_addr = (void *)zpage;
1219  dbufs[col].b_nob = pagesize;
1220  }
1221 
1222  for (col = 0; col < layout_k(play); ++col)
1223  pbufs[col] = map->pi_paritybufs[row][col]->
1224  db_buf;
1225 
1227  dbufs, pbufs);
1228  }
1229 
1230  m0_free_aligned(zpage, 1ULL<<obj->ob_attr.oa_bshift,
1231  M0_NETBUF_SHIFT);
1232  M0_LOG(M0_DEBUG, "Parity recalculated for %s",
1233  map->pi_rtype == PIR_READREST ? "read-rest" :
1234  "aligned write");
1235 
1236  } else {
1237  struct m0_buf *old;
1238 
1239  M0_ALLOC_ARR(old, layout_n(play));
1240  if (old == NULL) {
1241  rc = -ENOMEM;
1242  goto last;
1243  }
1244 
1245  for (row = 0; row < rows_nr(play, ioo->ioo_obj); ++row) {
1246  for (col = 0; col < layout_k(play); ++col)
1247  pbufs[col] = map->pi_paritybufs[row][col]->
1248  db_buf;
1249 
1250  for (col = 0; col < layout_n(play); ++col) {
1251  /*
1252  * During rmw-IO request with read-old approach
1253  * we allocate primary and auxiliary buffers
1254  * for those units from a parity group, that
1255  * are spanned by input rmw-IO request. If
1256  * these units belong to failed devices then
1257  * during the degraded reading, primary buffers
1258  * are allocated for rest of the units from the
1259  * parity group in order to recover the failed
1260  * units. Thus if a parity group is in dgmode,
1261  * then every unit will have a primary buffer,
1262  * but may not have an auxiliary buffer.
1263  */
1264  if (map->pi_databufs[row][col] == NULL ||
1265  map->pi_databufs[row][col]->
1266  db_auxbuf.b_addr == NULL)
1267  continue;
1268 
1269  dbufs[col] = map->pi_databufs[row][col]->db_buf;
1270  old[col] = map->pi_databufs[row][col]->db_auxbuf;
1272  old, dbufs, pbufs, col);
1273  if (rc != 0) {
1274  m0_free(old);
1275  goto last;
1276  }
1277  }
1278  }
1279  m0_free(old);
1280  }
1281 last:
1282  m0_free(dbufs);
1283  m0_free(pbufs);
1284 
1285  return M0_RC(rc);
1286 }
1287 
1297 {
1298  uint32_t row;
1299  uint32_t col;
1300  struct m0_pdclust_layout *play;
1301  struct m0_client *instance;
1302  struct m0_obj *obj;
1303  struct m0_op *op;
1304  unsigned int op_code;
1305  struct data_buf *dbuf;
1306  void *pbuf;
1307  void *ptr;
1310  uint32_t num_alloc;
1311  uint32_t row_per_seg;
1312  uint32_t i;
1313  struct data_buf *buf;
1314 
1315  M0_ENTRY("[%p] map %p", map->pi_ioo, map);
1316 
1318  obj = map->pi_ioo->ioo_obj;
1319  op = &map->pi_ioo->ioo_oo.oo_oc.oc_op;
1321  op_code = op->op_code;
1322 
1323  play = pdlayout_get(map->pi_ioo);
1324  seg_size = instance->m0c_ndom.nd_get_max_buffer_segment_size;
1325  unit_size = layout_unit_size(play);
1326 
1327  if (unit_size > seg_size)
1328  num_alloc = unit_size / seg_size;
1329  else
1330  num_alloc = 1;
1331 
1332  row_per_seg = rows_nr(play, obj) / num_alloc;
1333 
1334  for (col = 0; col < layout_k(play); ++col) {
1335  for (i = 0; i < num_alloc; ++i) {
1337  M0_NETBUF_SHIFT);
1338  if (pbuf == NULL)
1339  goto err;
1340 
1341  ptr = pbuf;
1342  for (row = 0; row < row_per_seg; ++row) {
1343  M0_ALLOC_PTR(map->pi_paritybufs[
1344  (i*row_per_seg)+ row][col]);
1345  if (map->pi_paritybufs[
1346  (i*row_per_seg)+ row][col] == NULL)
1347  goto err;
1348 
1349  dbuf = map->pi_paritybufs[
1350  (i*row_per_seg)+ row][col];
1352  PA_NONE);
1353  ptr += obj_buffer_size(obj);
1354 
1355  M0_LOG(M0_DEBUG, "row=%d col=%d dbuf=%p pbuf=%p ptr=%p",
1356  row, col, dbuf, pbuf, ptr);
1357 
1358  if (M0_IN(op_code, (M0_OC_WRITE,
1359  M0_OC_FREE)))
1360  dbuf->db_flags |= PA_WRITE;
1361 
1362  if (map->pi_rtype == PIR_READOLD ||
1363  (op_code == M0_OC_READ &&
1364  instance->m0c_config->mc_is_read_verify))
1365  dbuf->db_flags |= PA_READ;
1366  }
1367  }
1368  }
1369 
1370  return M0_RC(0);
1371 err:
1372  for (i = 0; i < col; ++i) {
1373  for (row = 0; row < rows_nr(play, obj); ++row) {
1374  buf = map->pi_paritybufs[row][col];
1375  if (buf != NULL) {
1376  if ((row % row_per_seg) == 0 )
1377  m0_buf_free(&buf->db_buf);
1378  data_buf_fini(buf);
1379  m0_free(buf);
1380  }
1381  }
1382  }
1383 
1384  return M0_ERR(-ENOMEM);
1385 }
1386 
1388 {
1389  int row;
1390  int col;
1391  struct m0_pdclust_layout *play;
1392  struct m0_obj *obj;
1393  struct m0_op *op;
1394  struct data_buf *dbuf;
1395 
1396  M0_ENTRY("[%p] map %p", map->pi_ioo, map);
1397 
1399 
1400  obj = map->pi_ioo->ioo_obj;
1401  op = &map->pi_ioo->ioo_oo.oo_oc.oc_op;
1402 
1404 
1405  play = pdlayout_get(map->pi_ioo);
1406  for (row = 0; row < rows_nr(play, obj); ++row) {
1407  for (col = 0; col < layout_k(play); ++col) {
1408  if (map->pi_databufs[row][0] == NULL) {
1409  map->pi_paritybufs[row][col] =
1411  if (map->pi_paritybufs[row][col] == NULL) {
1412  goto err;
1413  }
1414  continue;
1415  } else {
1416  map->pi_paritybufs[row][col] =
1418  PA_NONE);
1419  if (map->pi_paritybufs[row][col] == NULL) {
1420  goto err;
1421  }
1422  }
1423  dbuf = map->pi_paritybufs[row][col];
1424  if (op->op_code == M0_OC_WRITE)
1425  dbuf->db_flags |= PA_WRITE;
1426  }
1427  }
1428 
1429  return M0_RC(0);
1430 err:
1431  for (; row > -1; --row) {
1432  for (col = 0; col < layout_k(play); ++col) {
1433  if (map->pi_databufs[row][0] == NULL) {
1435  pi_paritybufs[row][col]);
1436  map->pi_paritybufs[row][col] = NULL;
1437  } else
1438  m0_free0(&map->pi_paritybufs[row][col]);
1439  }
1440  }
1441 
1442  return M0_ERR(-ENOMEM);
1443 
1444 }
1445 
1459 {
1460  int rc = 0;
1461  uint32_t row;
1462  uint32_t row_nr;
1463  uint32_t col;
1464  uint32_t col_nr;
1465  struct data_buf ***bufs;
1466  struct m0_pdclust_layout *play;
1467  struct m0_op_io *ioo;
1468 
1469  M0_PRE(map != NULL);
1470  M0_PRE(M0_IN(type, (M0_PUT_DATA, M0_PUT_PARITY)));
1471  M0_ENTRY("[%p] map %p", map->pi_ioo, map);
1472 
1473  ioo = map->pi_ioo;
1474  play = pdlayout_get(ioo);
1475 
1476  if (type == M0_PUT_DATA) {
1477  M0_ASSERT(map->pi_databufs != NULL);
1478  row_nr = rows_nr(play, ioo->ioo_obj);
1479  col_nr = layout_n(play);
1480  bufs = map->pi_databufs;
1481  } else {
1482  row_nr = rows_nr(play, ioo->ioo_obj);
1483  col_nr = layout_k(play);
1484  bufs = map->pi_paritybufs;
1485  }
1486 
1487  /*
1488  * Allocates data_buf structures from either ::pi_databufs
1489  * or ::pi_paritybufs array.
1490  * The loop traverses the matrix, column (unit) by column (unit).
1491  */
1492  for (col = 0; col < col_nr; ++col) {
1493  for (row = 0; row < row_nr; ++row) {
1494  /*
1495  * If the page is marked as PA_READ_FAILED, all
1496  * other pages belonging to the unit same as
1497  * the failed one, are also marked as PA_READ_FAILED,
1498  * hence the loop breaks from here.
1499  */
1500  if (bufs[row][col] != NULL &&
1501  bufs[row][col]->db_flags & PA_READ_FAILED)
1502  break;
1503  }
1504 
1505  if (row == row_nr)
1506  continue;
1507  if (type == M0_PUT_PARITY) {
1508  /*
1509  * Setting parity buffer type to M0_PBUF_DIR, So that
1510  * it will free the buffer allocated for dgread path.
1511  * This buffer will be freed in
1512  * pargrp_iomap_fini() --> data_buf_dealloc_fini()
1513  */
1514  ioo->ioo_pbuf_type = M0_PBUF_DIR;
1515  }
1516  for (row = 0; row < row_nr; ++row) {
1517  if (bufs[row][col] == NULL) {
1518  bufs[row][col] =
1520  if (bufs[row][col] == NULL) {
1521  rc = -ENOMEM;
1522  break;
1523  }
1524  }
1525  bufs[row][col]->db_flags |= PA_READ_FAILED;
1526  }
1527  }
1528  return M0_RC(rc);
1529 }
1530 
1541 static int unit_state(const struct m0_pdclust_src_addr *src,
1542  struct m0_op_io *ioo,
1543  enum m0_pool_nd_state *state)
1544 {
1545  int rc;
1546  struct m0_pdclust_instance *play_instance;
1547  struct m0_pdclust_tgt_addr tgt;
1548  struct m0_poolmach *pm;
1549 
1550  M0_ENTRY();
1551 
1552  M0_PRE(src != NULL);
1553  M0_PRE(ioo != NULL);
1554  M0_PRE(state != NULL);
1555 
1556  play_instance = pdlayout_instance(layout_instance(ioo));
1557  m0_fd_fwd_map(play_instance, src, &tgt);
1558 
1559  pm = ioo_to_poolmach(ioo);
1560  M0_ASSERT(pm != NULL);
1561  rc = m0_poolmach_device_state(pm, tgt.ta_obj, state);
1562  if (rc != 0)
1563  return M0_ERR(rc);
1564 
1565  return M0_RC(rc);
1566 }
1567 
1580 static int io_spare_map(const struct pargrp_iomap *map,
1581  const struct m0_pdclust_src_addr *src,
1582  uint32_t *spare_slot, uint32_t *spare_slot_prev,
1583  enum m0_pool_nd_state *eff_state)
1584 {
1585 
1586  int rc;
1587  const struct m0_fid *gfid;
1588  struct m0_pdclust_layout *play;
1589  struct m0_pdclust_instance *play_instance;
1590  struct m0_pdclust_src_addr spare;
1591  struct m0_op_io *ioo;
1592  struct m0_poolmach *pm;
1593 
1594  M0_PRE(map != NULL);
1595  M0_PRE(map->pi_ioo != NULL);
1596  M0_PRE(src != NULL);
1597  M0_PRE(spare_slot != NULL);
1598  M0_PRE(spare_slot_prev != NULL);
1599  M0_PRE(eff_state != NULL);
1600 
1601  ioo = map->pi_ioo;
1602  play = pdlayout_get(ioo);
1603  play_instance = pdlayout_instance(layout_instance(ioo));
1604  gfid = &ioo->ioo_oo.oo_fid;
1605  pm = ioo_to_poolmach(ioo);
1606  M0_ASSERT(pm != NULL);
1607  rc = m0_sns_repair_spare_map(pm, gfid, play, play_instance,
1608  src->sa_group, src->sa_unit,
1609  spare_slot, spare_slot_prev);
1610  if (rc != 0)
1611  return M0_ERR(rc);
1612 
1613  /* Check if there is an effective failure of unit. */
1614  spare.sa_group = src->sa_group;
1615  spare.sa_unit = *spare_slot_prev;
1616  rc = unit_state(&spare, ioo, eff_state);
1617  return M0_RC(rc);
1618 }
1619 
1631 static void mark_page_as_read_failed(struct pargrp_iomap *map, uint32_t row,
1632  uint32_t col, enum page_attr page_type)
1633 {
1634  struct m0_pdclust_layout *play;
1635  struct m0_pdclust_src_addr src;
1636  enum m0_pool_nd_state state;
1637  uint32_t spare_slot;
1638  uint32_t spare_prev;
1639  int rc;
1640 
1641  M0_PRE(M0_IN(page_type,(PA_DATA, PA_PARITY)));
1642  M0_PRE(map != NULL);
1643  M0_PRE(ergo(page_type == PA_DATA,
1644  map->pi_databufs[row][col] != NULL));
1645  M0_PRE(ergo(page_type == PA_PARITY,
1646  map->pi_paritybufs[row][col] != NULL));
1647 
1648  M0_ENTRY("pid=%" PRIu64 ", row = %u, col=%u, type=0x%x",
1649  map->pi_grpid, row, col, page_type);
1650 
1651  play = pdlayout_get(map->pi_ioo);
1652  src.sa_group = map->pi_grpid;
1653  if (page_type == PA_DATA)
1654  src.sa_unit = col;
1655  else
1656  src.sa_unit = col + layout_n(play);
1657 
1658  rc = unit_state(&src, map->pi_ioo, &state);
1659  M0_ASSERT(rc == 0);
1660  if (state == M0_PNDS_SNS_REPAIRED) {
1661  /* gets the state of corresponding spare unit */
1662  rc = io_spare_map(map, &src, &spare_slot, &spare_prev,
1663  &state);
1664  M0_ASSERT(rc == 0);
1665  }
1666 
1667  /*
1668  * Checking state M0_PNDS_SNS_REBALANCING allows concurrent read during
1669  * sns rebalancing in oostore mode, this works similar to M0_PNDS_FAILED.
1670  * To handle concurrent i/o in non-oostore mode, some more changes are
1671  * required to write data to live unit (on earlier failed device) if the
1672  * device state is M0_PNDS_SNS_REBALANCING.
1673  */
1674  if (M0_IN(state, (M0_PNDS_FAILED, M0_PNDS_OFFLINE,
1676  if (page_type == PA_DATA)
1677  map->pi_databufs[row][col]->db_flags |=
1679  else
1680  map->pi_paritybufs[row][col]->db_flags |=
1682  }
1683 
1684  M0_LEAVE();
1685 }
1686 
1705  struct target_ioreq *tio,
1706  m0_bindex_t *index,
1707  uint32_t count)
1708 {
1709  int rc = 0;
1710  uint32_t row;
1711  uint32_t col;
1712  uint32_t spare_slot;
1713  uint32_t spare_slot_prev;
1714  m0_bindex_t goff;
1715  struct m0_pdclust_layout *play;
1716  struct m0_pdclust_src_addr src;
1717  struct m0_poolmach *pm;
1718  enum m0_pool_nd_state dev_state;
1719  struct m0_op_io *ioo;
1720  m0_bindex_t grp_size;
1721 
1723  M0_PRE(tio != NULL);
1724  M0_PRE(index != NULL);
1725  /*M0_PRE(count > 0);*/
1726  M0_ENTRY("grpid = %3" PRIu64 ", count = %u\n", map->pi_grpid, count);
1727 
1728  ioo = map->pi_ioo;
1729  play = pdlayout_get(ioo);
1730  pargrp_src_addr(index[0], ioo, tio, &src);
1731  M0_ASSERT(src.sa_group == map->pi_grpid);
1732  M0_ASSERT(src.sa_unit < layout_n(play) + layout_k(play));
1733  grp_size = data_size(play) * map->pi_grpid;
1734 
1735  /* Retrieve device state */
1736  pm = ioo_to_poolmach(ioo);
1737  M0_ASSERT(pm != NULL);
1738  rc = m0_poolmach_device_state(pm, tio->ti_obj, &dev_state);
1739  if (rc != 0)
1740  return M0_ERR(rc);
1741  if (dev_state == M0_PNDS_SNS_REPAIRED) {
1742  /*
1743  * If a device has just been repaired, a different layout
1744  * (using spare units) is used and new requests need to be sent.
1745  * But it's necessary to check whether the spare to which the
1746  * original unit has been mapped during repair is alive. In case
1747  * it's not online the degraded mode is invoked.
1748  */
1749  rc = io_spare_map(map, &src, &spare_slot, &spare_slot_prev,
1750  &dev_state);
1751  M0_ASSERT(rc == 0);
1752  if (dev_state == M0_PNDS_SNS_REPAIRED)
1753  return M0_RC(0);
1754  }
1755 
1756  map->pi_state = PI_DEGRADED;
1757  ++map->pi_ioo->ioo_dgmap_nr;
1758 
1759  /* Failed segment belongs to a data unit. */
1760  if (src.sa_unit < layout_n(play)) {
1761  goff = gobj_offset(index[0], map, play, &src);
1762  page_pos_get(map, goff, grp_size, &row, &col);
1763  M0_ASSERT(map->pi_databufs[row][col] != NULL);
1764  map->pi_databufs[row][col]->db_flags |= PA_READ_FAILED;
1765  } else {
1766  /* Failed segment belongs to a parity unit. */
1767  row = page_nr(index[0], ioo->ioo_obj)
1768  % page_nr(layout_unit_size(play), ioo->ioo_obj);
1769  col = src.sa_unit - layout_n(play);
1770  M0_ASSERT(map->pi_paritybufs[row][col] != NULL);
1771  map->pi_paritybufs[row][col]->db_flags |= PA_READ_FAILED;
1772  }
1773 
1774  /*
1775  * Since m0_parity_math_recover() API will recover one or more
1776  * _whole_ units, all pages from a failed unit can be marked as
1777  * PA_READ_FAILED. These pages need not be read again.
1778  */
1780  if (rc != 0)
1781  return M0_ERR(rc);
1782 
1783  /*
1784  * If parity buffers are not allocated, they should be allocated
1785  * since they are needed for recovering lost data.
1786  */
1787  if (map->pi_paritybufs == NULL) {
1788  M0_ALLOC_ARR(map->pi_paritybufs, rows_nr(play, ioo->ioo_obj));
1789  if (map->pi_paritybufs == NULL)
1790  return M0_ERR(-ENOMEM);
1791 
1792  for (row = 0; row < rows_nr(play, ioo->ioo_obj); ++row) {
1793  M0_ALLOC_ARR(map->pi_paritybufs[row], layout_k(play));
1794  if (map->pi_paritybufs[row] == NULL) {
1795  rc = -ENOMEM;
1796  goto par_fail;
1797  }
1798  }
1799  }
1801  return M0_RC(rc);
1802 
1803 par_fail:
1804  M0_ASSERT(rc != 0);
1805  for (row = 0; row < rows_nr(play, ioo->ioo_obj); ++row)
1806  m0_free0(&map->pi_paritybufs[row]);
1807  m0_free0(&map->pi_paritybufs);
1808 
1809  return M0_ERR(rc);
1810 }
1811 
1823 {
1824  int rc = 0;
1825  uint32_t row;
1826  uint32_t col;
1827  struct data_buf *dbuf;
1828  struct m0_pdclust_layout *play;
1829  struct m0_client *instance;
1830  struct m0_op_io *ioo;
1831  struct m0_obj *obj;
1832 
1833  /*
1834  * read_old: Reads unavailable data subject to condition that
1835  * data lies within file size. Parity is already read.
1836  * read_rest: Reads parity units. Data for parity group is already
1837  * read.
1838  * simple_read: Reads unavailable data subject to condition that
1839  * data lies within file size. Parity also has to be read.
1840  */
1842  M0_ENTRY("parity group id %3" PRIu64 ", map state = %d",
1843  map->pi_grpid, map->pi_state);
1844 
1845  ioo = map->pi_ioo;
1846  play = pdlayout_get(ioo);
1847  obj = ioo->ioo_obj;
1849 
1850  /*
1851  * Data matrix from parity group.
1852  * The loop traverses column by column to be in sync with
1853  * increasing file offset.
1854  * This is necessary in order to generate correct index vector.
1855  */
1856  for (col = 0; col < layout_n(play); ++col) {
1857  for (row = 0; row < rows_nr(play, obj); ++row) {
1858 
1859  if (map->pi_databufs[row][col] != NULL &&
1860  map->pi_databufs[row][col]->db_flags &
1861  PA_READ_FAILED) {
1862  continue;
1863  } else {
1864  /*
1865  * If current parity group map is degraded,
1866  * then recovery is needed and a new
1867  * data buffer needs to be allocated subject to
1868  * limitation of file size.
1869  */
1870  if (map->pi_state == PI_DEGRADED) {
1871  map->pi_databufs[row][col] =
1873  if (map->pi_databufs[row][col] ==
1874  NULL) {
1875  rc = -ENOMEM;
1876  break;
1877  }
1878  mark_page_as_read_failed(map, row, col,
1879  PA_DATA);
1880  }
1881  if (map->pi_state == PI_HEALTHY)
1882  continue;
1883  }
1884  dbuf = map->pi_databufs[row][col];
1885 
1886  if (dbuf->db_flags & PA_READ_FAILED
1887  || is_page_read(dbuf)) {
1888  continue;
1889  }
1890  dbuf->db_flags |= PA_DGMODE_READ;
1891  }
1892  }
1893 
1894  if (rc != 0)
1895  goto err;
1896  /* If parity group is healthy, there is no need to read parity. */
1897  if (map->pi_state != PI_DEGRADED &&
1898  !instance->m0c_config->mc_is_read_verify)
1899  return M0_RC(0);
1900 
1901  /*
1902  * Populates the index vector if original read IO request did not
1903  * span it. Since recovery is needed using parity algorithms,
1904  * whole parity group needs to be read subject to file size limitation.
1905  * Ergo, parity group index vector contains only one segment
1906  * worth the parity group in size.
1907  */
1908  INDEX(&map->pi_ivec, 0) = map->pi_grpid * data_size(play);
1909  COUNT(&map->pi_ivec, 0) = data_size(play);
1910 
1911  /*
1912  * m0_0vec requires all members except the last one to have data count
1913  * multiple of 4K.
1914  */
1915  COUNT(&map->pi_ivec, 0) = round_up(COUNT(&map->pi_ivec, 0),
1916  m0__page_size(ioo));
1917  SEG_NR(&map->pi_ivec) = 1;
1918  /*indexvec_dump(&map->pi_ivec);*/
1919 
1920  /* parity matrix from parity group. */
1921  for (row = 0; row < rows_nr(play, obj); ++row) {
1922  for (col = 0; col < layout_k(play); ++col) {
1923 
1924  if (map->pi_paritybufs[row][col] == NULL) {
1925  map->pi_paritybufs[row][col] =
1927  if (map->pi_paritybufs[row][col] == NULL) {
1928  rc = -ENOMEM;
1929  break;
1930  }
1931  }
1932  dbuf = map->pi_paritybufs[row][col];
1934  /* Skips the page if it is marked as PA_READ_FAILED. */
1935  if (dbuf->db_flags & PA_READ_FAILED ||
1936  is_page_read(dbuf)) {
1937  continue;
1938  }
1939  dbuf->db_flags |= PA_DGMODE_READ;
1940  }
1941  }
1942  if (rc != 0)
1943  goto err;
1944  return M0_RC(rc);
1945 err:
1946  return M0_ERR(rc);
1947 }
1948 
1950  uint8_t *failed)
1951 {
1952  struct m0_pdclust_layout *play;
1953  uint32_t col;
1954  uint32_t K = 0;
1955 
1956  play = pdlayout_get(map->pi_ioo);
1957  for (col = 0; col < layout_n(play); ++col) {
1958  if (map->pi_databufs[0][col] != NULL &&
1959  map->pi_databufs[0][col]->db_flags &
1960  PA_READ_FAILED) {
1961  failed[col] = 1;
1962  ++K;
1963  }
1964 
1965  }
1966  for (col = 0; col < layout_k(play); ++col) {
1967  M0_ASSERT(map->pi_paritybufs[0][col] != NULL);
1968  if (map->pi_paritybufs[0][col]->db_flags &
1969  PA_READ_FAILED) {
1970  failed[col + layout_n(play)] = 1;
1971  ++K;
1972  }
1973  }
1974  return K;
1975 }
1976 
1986 {
1987  int rc = 0;
1988  uint32_t row;
1989  uint32_t col;
1990  uint32_t K;
1991  uint64_t pagesize;
1992  void *zpage;
1993  struct m0_buf *data;
1994  struct m0_buf *parity;
1995  struct m0_buf failed;
1996  struct m0_pdclust_layout *play;
1997  struct m0_op_io *ioo;
1998 
1999  M0_ENTRY();
2001  M0_PRE(map->pi_state == PI_DEGRADED);
2002 
2003  ioo = map->pi_ioo;
2004  play = pdlayout_get(ioo);
2005  pagesize = m0__page_size(ioo);
2006 
2007  M0_ALLOC_ARR(data, layout_n(play));
2008  if (data == NULL)
2009  return M0_ERR_INFO(-ENOMEM, "Failed to allocate memory"
2010  " for data buf");
2011 
2012  M0_ALLOC_ARR(parity, layout_k(play));
2013  if (parity == NULL) {
2014  m0_free(data);
2015  return M0_ERR_INFO(-ENOMEM, "Failed to allocate memory"
2016  " for parity buf");
2017  }
2018 
2019  zpage = m0_alloc_aligned(pagesize, M0_NETBUF_SHIFT);
2020  if (zpage == 0) {
2021  m0_free(data);
2022  m0_free(parity);
2023  return M0_ERR_INFO(-ENOMEM, "Failed to allocate page.");
2024  }
2025 
2026  failed.b_nob = layout_n(play) + layout_k(play);
2027 
2028  failed.b_addr = m0_alloc(failed.b_nob);
2029  if (failed.b_addr == NULL) {
2030  m0_free(data);
2031  m0_free(parity);
2032  m0_free_aligned(zpage, pagesize, M0_NETBUF_SHIFT);
2033  return M0_ERR_INFO(-ENOMEM, "Failed to allocate memory "
2034  "for m0_buf");
2035  }
2036 
2037  K = iomap_dgmode_recov_prepare(map, (uint8_t *)failed.b_addr);
2038  if (K > layout_k(play)) {
2039  M0_LOG(M0_ERROR, "More failures in group %d",
2040  (int)map->pi_grpid);
2041  rc = -EIO;
2042  goto end;
2043  }
2044 
2045  /* Populates data and failed buffers. */
2046  for (row = 0; row < rows_nr(play, ioo->ioo_obj); ++row) {
2047  for (col = 0; col < layout_n(play); ++col) {
2048  data[col].b_nob = pagesize;
2049 
2050  if (map->pi_databufs[row][col] == NULL) {
2051  data[col].b_addr = (void *)zpage;
2052  continue;
2053  }
2054  data[col].b_addr = map->pi_databufs[row][col]->
2055  db_buf.b_addr;
2056  }
2057 
2058  for (col = 0; col < layout_k(play); ++col) {
2059  M0_ASSERT(map->pi_paritybufs[row][col] != NULL);
2060  parity[col].b_addr =
2061  map->pi_paritybufs[row][col]->db_buf.b_addr;
2062  parity[col].b_nob = pagesize;
2063  }
2064 
2066  parity, &failed, M0_LA_INVERSE);
2067  if (rc != 0)
2068  goto end;
2069  }
2070 
2071 end:
2072  m0_free(data);
2073  m0_free(parity);
2074  m0_free(failed.b_addr);
2075  m0_free_aligned(zpage, pagesize, M0_NETBUF_SHIFT);
2076 
2077  return rc == 0 ?
2078  M0_RC(rc) :
2079  M0_ERR_INFO(-EIO,
2080  "Number of failed units"
2081  "in parity group exceeds the"
2082  "total number of parity units"
2083  "in a parity group %d.", (int)map->pi_grpid);
2084 }
2085 
2086 static bool crc_cmp(const struct m0_buf *val1, const struct m0_buf *val2)
2087 {
2088  return *(uint32_t *)val1->b_addr == *(uint32_t *)val2->b_addr;
2089 }
2090 
2091 static void db_crc_set(struct data_buf *dbuf, uint32_t key,
2092  struct m0_key_val *kv)
2093 {
2094  m0_crc32(dbuf->db_buf.b_addr, dbuf->db_buf.b_nob,
2095  (void *)&dbuf->db_crc);
2096  dbuf->db_key = key;
2097  m0_key_val_init(kv, &M0_BUF_INIT_PTR(&dbuf->db_key),
2098  &M0_BUF_INIT_PTR(&dbuf->db_crc));
2099 }
2100 
2101 static size_t offset_get(struct pargrp_iomap *map)
2102 {
2103  struct m0_pdclust_layout *play;
2104  struct m0_op_io *ioo;
2105 
2106  ioo = map->pi_ioo;
2107  play = pdlayout_get(ioo);
2108 
2109  return m0_pdclust_unit_size(play) * map->pi_grpid;
2110 }
2111 
2113 {
2114  int rc = 0;
2115  uint32_t row;
2116  uint32_t col;
2117  uint32_t crc_idx;
2118  uint32_t vote_nr;
2119  size_t offset;
2120  struct m0_pdclust_layout *play;
2121  struct m0_client *instance;
2122  struct m0_op_io *ioo;
2123  struct m0_op *op;
2124  struct m0_key_val *crc_arr;
2125  struct data_buf *dbuf;
2126  struct data_buf *pbuf;
2127  struct m0_key_val *mjr;
2128  uint32_t unit_id;
2129 
2130  M0_ENTRY("map = %p", map);
2132 
2133  ioo = map->pi_ioo;
2134  op = &ioo->ioo_oo.oo_oc.oc_op;
2136 
2137  if (map->pi_state != PI_DEGRADED &&
2138  !(op->op_code == M0_OC_READ &&
2139  instance->m0c_config->mc_is_read_verify))
2140  return M0_RC(0);
2141 
2142  play = pdlayout_get(ioo);
2143  M0_ALLOC_ARR(crc_arr, layout_n(play) + layout_k(play));
2144 
2145  if (crc_arr == NULL) {
2146  rc = M0_ERR(-ENOMEM);
2147  goto last;
2148  }
2149 
2150  /*
2151  * Parity comparison is done only in the case of a replicated layout.
2152  * Assume that for a 1 + K replicated layout K = 3. Then we have the
2153  * following layout of pages for a single parity group.
2154  *
2155  * \ col
2156  *row +---+---+---+---+
2157  * | D | P | P | P |
2158  * +---+---+---+---+
2159  * | D | P | P | P |
2160  * +---+---+---+---+
2161  * | D | P | P | P |
2162  * +---+---+---+---+
2163  * Each block represents a page sized data. All members of a row shall
2164  * be identical in ideal case (due to replication). We calculate CRC
2165  * for each page and check if all members of a row have an identical
2166  * CRC. The page corresponding to the value that holds majority in
2167  * a row shall be returned to user.
2168  */
2169  for (row = 0, crc_idx = 0; row < rows_nr(play, ioo->ioo_obj);
2170  ++row, crc_idx = 0) {
2171  dbuf = map->pi_databufs[row][0];
2172  /* Degraded pages won't contend the election. */
2173  if (dbuf->db_flags & PA_READ_FAILED)
2174  dbuf->db_crc = 0;
2175  else {
2176  unit_id = 0;
2177  db_crc_set(dbuf, unit_id, &crc_arr[crc_idx++]);
2178  }
2179  for (col = 0; col < layout_k(play); ++col) {
2180  pbuf = map->pi_paritybufs[row][col];
2181  if (pbuf->db_flags & PA_READ_FAILED)
2182  pbuf->db_crc = 0;
2183  /*
2184  * Only if a page is not degraded it contends
2185  * the election.
2186  */
2187  else {
2188  /* Shift by one to count for the data unit. */
2189  unit_id = col + 1;
2190  db_crc_set(pbuf, unit_id, &crc_arr[crc_idx++]);
2191  }
2192  }
2193  vote_nr = 0;
2194  mjr = m0_vote_majority_get(crc_arr, crc_idx, crc_cmp,
2195  &vote_nr);
2196  if (mjr == NULL) {
2197  M0_LOG(M0_ERROR, "[%p] parity verification "
2198  "failed for %llu [%u:%u], rc %d",
2199  map->pi_ioo, (unsigned long long)map->pi_grpid,
2200  row, col, -EIO);
2201  rc = M0_ERR(-EIO);
2202  goto last;
2203  }
2204 
2205  M0_ASSERT(vote_nr >= crc_idx/2 + 1);
2206  if (vote_nr < crc_idx) {
2208  offset = offset_get(map);
2209  M0_LOG(M0_WARN, "Discrepancy observed at offset %d",
2210  (int)offset);
2211  map->pi_is_corrupted = true;
2212  ioo->ioo_rect_needed = true;
2213  }
2218  map->pi_databufs[row][0]->db_maj_ele = *mjr;
2219  for (col = 0; col < layout_k(play); ++col) {
2220  map->pi_paritybufs[row][col]->db_maj_ele = *mjr;
2221  }
2222  }
2223 last:
2224 
2225  m0_free(crc_arr);
2226  M0_LOG(M0_DEBUG, "parity verified for %" PRIu64 " rc=%d",
2227  map->pi_grpid, rc);
2228  return M0_RC(rc);
2229 }
2230 
2232 {
2233  int rc;
2234  uint32_t row;
2235  uint32_t col;
2236  uint64_t pagesize;
2237  struct m0_buf *dbufs;
2238  struct m0_buf *pbufs;
2239  struct m0_buf *old_pbuf;
2240  struct m0_pdclust_layout *play;
2241  struct page *page;
2242  struct m0_client *instance;
2243  struct m0_op_io *ioo;
2244  struct m0_op *op;
2245  void *zpage;
2246 
2247  M0_ENTRY("map = %p", map);
2249 
2250  ioo = map->pi_ioo;
2251  op = &ioo->ioo_oo.oo_oc.oc_op;
2253  pagesize = m0__page_size(ioo);
2254 
2255  if (!(op->op_code == M0_OC_READ &&
2256  instance->m0c_config->mc_is_read_verify))
2257  return M0_RC(0);
2258 
2259  play = pdlayout_get(ioo);
2260  M0_ALLOC_ARR(dbufs, layout_n(play));
2261  M0_ALLOC_ARR(pbufs, layout_k(play));
2262  zpage = m0_alloc_aligned(pagesize, M0_NETBUF_SHIFT);
2263 
2264  if (dbufs == NULL || pbufs == NULL || zpage == NULL) {
2265  rc = M0_ERR(-ENOMEM);
2266  goto last;
2267  }
2268 
2269  /* temprary buf to hold parity */
2270  for (col = 0; col < layout_k(play); ++col) {
2271  page = m0_alloc_aligned(pagesize, M0_NETBUF_SHIFT);
2272  if (page == NULL) {
2273  rc = M0_ERR(-ENOMEM);
2274  goto last;
2275  }
2276 
2277  pbufs[col].b_addr = (void *)page;
2278  pbufs[col].b_nob = pagesize;
2279  }
2280 
2281  for (row = 0; row < rows_nr(play, ioo->ioo_obj); ++row) {
2282  /* data */
2283  for (col = 0; col < layout_n(play); ++col) {
2284  if (map->pi_databufs[row][col] != NULL) {
2285  dbufs[col] =
2286  map->pi_databufs[row][col]->db_buf;
2287  } else {
2288  dbufs[col].b_addr = zpage;
2289  dbufs[col].b_nob = pagesize;
2290  }
2291  }
2292 
2293  /* generate parity into new buf */
2295  dbufs, pbufs);
2296 
2297  /* verify the parity */
2298  for (col = 0; col < layout_k(play); ++col) {
2299  old_pbuf = &map->pi_paritybufs[row][col]->db_buf;
2300  if (memcmp(pbufs[col].b_addr, old_pbuf->b_addr,
2301  pagesize)) {
2302  M0_LOG(M0_ERROR, "[%p] parity verification "
2303  "failed for %llu [%u:%u], rc %d",
2304  map->pi_ioo,
2305  (unsigned long long)map->pi_grpid, row,
2306  col, -EIO);
2307  rc = M0_ERR(-EIO);
2308  goto last;
2309  }
2310  M0_LOG(M0_DEBUG,
2311  "parity verified for %" PRIu64 " [%u:%u]",
2312  map->pi_grpid, row, col);
2313  }
2314  }
2315 
2316  rc = 0;
2317 last:
2318  if (pbufs != NULL) {
2319  for (col = 0; col < layout_k(play); ++col) {
2320  if(pbufs[col].b_addr == NULL) continue;
2321 
2322  m0_free_aligned(pbufs[col].b_addr,
2323  pagesize, M0_NETBUF_SHIFT);
2324  }
2325  }
2326  m0_free(dbufs);
2327  m0_free(pbufs);
2328  m0_free_aligned(zpage, pagesize, M0_NETBUF_SHIFT);
2329  M0_LOG(M0_DEBUG, "parity verified for %" PRIu64 " rc=%d",
2330  map->pi_grpid, rc);
2331  return M0_RC(rc);
2332 }
2333 
2334 static const struct pargrp_iomap_ops iomap_ops = {
2336  .pi_spans_seg = pargrp_iomap_spans_seg,
2337  .pi_fullpages_find = pargrp_iomap_fullpages_count,
2338  .pi_seg_process = pargrp_iomap_seg_process,
2339  .pi_databuf_alloc = pargrp_iomap_databuf_alloc,
2340  .pi_readrest = pargrp_iomap_readrest,
2341  .pi_readold_auxbuf_alloc = pargrp_iomap_readold_auxbuf_alloc,
2342  .pi_parity_recalc = pargrp_iomap_parity_recalc,
2343  .pi_parity_verify = pargrp_iomap_parity_verify,
2344  .pi_parity_replica_verify = pargrp_iomap_replica_elect,
2345  .pi_data_replicate = pargrp_iomap_databuf_replicate,
2346  .pi_paritybufs_alloc = pargrp_iomap_paritybufs_alloc,
2347  .pi_dgmode_process = pargrp_iomap_dgmode_process,
2348  .pi_dgmode_postprocess = pargrp_iomap_dgmode_postprocess,
2349  .pi_dgmode_recover = pargrp_iomap_dgmode_recover,
2350  .pi_replica_recover = pargrp_iomap_replica_elect,
2351 };
2352 
2353 static void pargrp_iomap_bufs_free(struct data_buf ***bufs, int nr)
2354 {
2355  if (bufs == NULL)
2356  return;
2357  while (nr > 0)
2358  m0_free(bufs[--nr]);
2359  m0_free(bufs);
2360 }
2361 
2362 static int pargrp_iomap_bufs_alloc(struct data_buf ****bufs_out,
2363  uint32_t row_nr, uint32_t col_nr)
2364 {
2365  int row;
2366  struct data_buf ***bufs;
2367 
2368  M0_ALLOC_ARR(bufs, row_nr);
2369  if (bufs == NULL)
2370  return M0_ERR(-ENOMEM);
2371 
2372  for (row = 0; row < row_nr; ++row) {
2373  M0_ALLOC_ARR(bufs[row], col_nr);
2374  if (bufs[row] == NULL) {
2375  pargrp_iomap_bufs_free(bufs, row);
2376  return M0_ERR(-ENOMEM);
2377  }
2378  }
2379 
2380  *bufs_out = bufs;
2381  return 0;
2382 }
2383 
2387 M0_INTERNAL int pargrp_iomap_init(struct pargrp_iomap *map,
2388  struct m0_op_io *ioo,
2389  uint64_t grpid)
2390 {
2391  int rc;
2392  struct m0_pdclust_layout *play;
2393  struct m0_client *instance;
2394  struct m0_op *op;
2395 
2396  M0_ENTRY("map = %p, op_io = %p, grpid = %"PRIu64, map, ioo, grpid);
2397 
2398  M0_PRE(map != NULL);
2399  M0_PRE(ioo != NULL);
2400  op = &ioo->ioo_oo.oo_oc.oc_op;
2402  M0_PRE(instance != NULL);
2403 
2404  pargrp_iomap_bob_init(map);
2405  play = pdlayout_get(ioo);
2406  map->pi_ops = &iomap_ops;
2407  map->pi_rtype = PIR_NONE;
2408  map->pi_grpid = grpid;
2409  map->pi_ioo = ioo;
2410  map->pi_state = PI_HEALTHY;
2411  map->pi_paritybufs = NULL;
2412  map->pi_trunc_partial = false;
2413 
2414  rc = m0_indexvec_alloc(&map->pi_ivec,
2415  page_nr(data_size(play), ioo->ioo_obj));
2416  if (rc != 0)
2417  goto fail;
2418 
2419  /*
2420  * This number is incremented only when a valid segment
2421  * is added to the index vector.
2422  */
2423  map->pi_ivec.iv_vec.v_nr = 0;
2424 
2425  map->pi_max_row = rows_nr(play, ioo->ioo_obj);
2426  map->pi_max_col = layout_n(play);
2427 
2428  rc = pargrp_iomap_bufs_alloc(&map->pi_databufs,
2429  rows_nr(play, ioo->ioo_obj),
2430  layout_n(play));
2431  if (M0_FI_ENABLED("no-mem-err"))
2432  rc = -ENOMEM;
2433  if (rc != 0)
2434  goto fail;
2435  /*
2436  * Whether direct or indirect parity allocation, meta level buffers
2437  * are always allocated. Allocation of buffers holding actual parity
2438  * is governed by M0_PBUF_DIR/IND.
2439  */
2440  if (M0_IN(ioo->ioo_pbuf_type, (M0_PBUF_DIR, M0_PBUF_IND))) {
2441  rc = pargrp_iomap_bufs_alloc(&map->pi_paritybufs,
2442  rows_nr(play, ioo->ioo_obj),
2443  layout_k(play));
2444  if (rc != 0)
2445  goto fail;
2446  }
2447 
2449  return M0_RC(0);
2450 
2451 fail:
2452  pargrp_iomap_bufs_free(map->pi_databufs, rows_nr(play, ioo->ioo_obj));
2453  m0_indexvec_free(&map->pi_ivec);
2454 
2455  return M0_ERR(-ENOMEM);
2456 }
2457 
2458 static bool are_pbufs_allocated(struct m0_op_io *ioo)
2459 {
2460  return ioo->ioo_pbuf_type == M0_PBUF_DIR;
2461 }
2462 
2467 M0_INTERNAL void pargrp_iomap_fini(struct pargrp_iomap *map,
2468  struct m0_obj *obj)
2469 {
2470  uint32_t row;
2471  uint32_t col;
2472  uint32_t col_r; /* num of col in replicated layout */
2473  struct data_buf *buf;
2474  struct m0_pdclust_layout *play;
2477  struct m0_client *instance;
2478  struct m0_op *op;
2479  uint32_t num_alloc;
2480  uint32_t row_per_seg;
2481 
2482  M0_ENTRY("map %p", map);
2483 
2485  M0_PRE(obj != NULL);
2486 
2487  play = pdlayout_get(map->pi_ioo);
2488  map->pi_ops = NULL;
2489  map->pi_rtype = PIR_NONE;
2490  map->pi_state = PI_NONE;
2491 
2492  op = &map->pi_ioo->ioo_oo.oo_oc.oc_op;
2494 
2495  seg_size = instance->m0c_ndom.nd_get_max_buffer_segment_size;
2496  unit_size = layout_unit_size(play);
2497  if (unit_size > seg_size)
2498  num_alloc = unit_size / seg_size;
2499  else
2500  num_alloc = 1;
2501 
2502  row_per_seg = rows_nr(play, obj) / num_alloc;
2503 
2504  pargrp_iomap_bob_fini(map);
2505  m0_indexvec_free(&map->pi_ivec);
2506 
2507  for (row = 0; row < rows_nr(play, obj); ++row) {
2508  if (map->pi_ioo->ioo_pbuf_type == M0_PBUF_IND &&
2509  map->pi_databufs[row][0] == NULL) {
2510  for (col_r = 0; col_r < layout_k(play); ++col_r) {
2512  pi_paritybufs[row][col_r]);
2513  map->pi_paritybufs[row][col_r] = NULL;
2514  }
2515  }
2516 
2517  for (col = 0; col < layout_n(play); ++col) {
2518  if (map->pi_databufs[row][col] != NULL) {
2520  pi_databufs[row][col]);
2521  map->pi_databufs[row][col] = NULL;
2522  }
2523  }
2524 
2525  m0_free0(&map->pi_databufs[row]);
2526  }
2527 
2528  if (map->pi_paritybufs != NULL) {
2529  for (col = 0; col < layout_k(play); ++col) {
2530  for (row = 0; row < rows_nr(play, obj); ++row) {
2531  buf = map->pi_paritybufs[row][col];
2532  if (buf != NULL) {
2533  if (are_pbufs_allocated(map->pi_ioo) &&
2534  (row % row_per_seg) == 0 ) {
2536  } else {
2537  data_buf_fini(buf);
2538  m0_free(buf);
2539  }
2540  map->pi_paritybufs[row][col] = NULL;
2541  }
2542  }
2543  }
2544  }
2545 
2546  for (row = 0; row < rows_nr(play, obj); ++row) {
2547  if (map->pi_paritybufs != NULL)
2548  m0_free0(&map->pi_paritybufs[row]);
2549  }
2550 
2551  m0_free0(&map->pi_databufs);
2552  m0_free0(&map->pi_paritybufs);
2553  map->pi_ioo = NULL;
2554 
2555  M0_LEAVE();
2556 }
2557 
2558 #undef M0_TRACE_SUBSYSTEM
2559 
2560 /*
2561  * Local variables:
2562  * c-indentation-style: "K&R"
2563 
2564  * c-basic-offset: 8
2565  * tab-width: 8
2566  * fill-column: 80
2567  * scroll-step: 1
2568  * End:
2569  */
2570 /*
2571  * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap
2572  */
static m0_bcount_t seg_size
Definition: net.c:118
M0_INTERNAL void m0_ivec_cursor_init(struct m0_ivec_cursor *cur, const struct m0_indexvec *ivec)
Definition: vec.c:707
M0_BOB_DEFINE(M0_INTERNAL, &pgiomap_bobtype, pargrp_iomap)
static void ptr(struct m0_addb2__context *ctx, const uint64_t *v, char *buf)
Definition: dump.c:440
static size_t nr
Definition: dump.c:1505
#define M0_PRE(cond)
M0_INTERNAL bool m0_pdclust_is_replicated(struct m0_pdclust_layout *play)
Definition: pdclust.c:829
const struct m0_bob_type dtbuf_bobtype
Definition: io_pargrp.c:55
#define M0_ALLOC_ARR(arr, nr)
Definition: memory.h:84
static int pargrp_iomap_dgmode_process(struct pargrp_iomap *map, struct target_ioreq *tio, m0_bindex_t *index, uint32_t count)
Definition: io_pargrp.c:1704
#define COUNT(ivec, i)
Definition: file.c:392
uint32_t db_key
Definition: pg.h:214
Definition: client.h:788
M0_INTERNAL int m0_indexvec_alloc(struct m0_indexvec *ivec, uint32_t len)
Definition: vec.c:532
static uint32_t seg_nr
Definition: net.c:119
int const char const void size_t int flags
Definition: dir.c:328
uint64_t sa_group
Definition: pdclust.h:241
static m0_bcount_t seg_endpos(const struct m0_indexvec *ivec, uint32_t i)
Definition: file.c:420
#define NULL
Definition: misc.h:38
static uint64_t pargrp_iomap_fullpages_count(struct pargrp_iomap *map)
Definition: io_pargrp.c:685
map
Definition: processor.c:112
M0_INTERNAL m0_bcount_t m0_ivec_cursor_step(const struct m0_ivec_cursor *cur)
Definition: vec.c:726
static struct buffer * cur(struct m0_addb2_mach *mach, m0_bcount_t space)
Definition: addb2.c:791
#define ergo(a, b)
Definition: misc.h:293
M0_INTERNAL m0_bindex_t m0_ivec_cursor_conti(const struct m0_ivec_cursor *cur, m0_bindex_t dest)
Definition: vec.c:765
static bool data_buf_invariant_nr(const struct pargrp_iomap *map)
Definition: io_pargrp.c:160
static void mark_page_as_read_failed(struct pargrp_iomap *map, uint32_t row, uint32_t col, enum page_attr page_type)
Definition: io_pargrp.c:1631
void * b_addr
Definition: buf.h:39
static int pargrp_iomap_populate(struct pargrp_iomap *map, struct m0_ivec_cursor *cursor, struct m0_bufvec_cursor *buf_cursor)
Definition: io_pargrp.c:578
#define M0_LOG(level,...)
Definition: trace.h:167
M0_LEAVE()
static uint32_t layout_k(const struct m0_pdclust_layout *play)
Definition: file.c:520
static int pargrp_iomap_readrest(struct pargrp_iomap *map)
Definition: io_pargrp.c:1084
static int pargrp_iomap_parity_recalc(struct pargrp_iomap *map)
Definition: io_pargrp.c:1163
M0_INTERNAL bool data_buf_invariant(const struct data_buf *db)
Definition: io_pargrp.c:145
M0_INTERNAL int m0_sns_repair_spare_map(struct m0_poolmach *pm, const struct m0_fid *fid, struct m0_pdclust_layout *pl, struct m0_pdclust_instance *pi, uint64_t group, uint64_t unit, uint32_t *spare_slot_out, uint32_t *spare_slot_out_prev)
M0_INTERNAL void m0_buf_init(struct m0_buf *buf, void *data, uint32_t nob)
Definition: buf.c:37
struct m0_bufvec data
Definition: di.c:40
static bool is_page_read(struct data_buf *dbuf)
Definition: io_pargrp.c:136
uint64_t ta_obj
Definition: pdclust.h:256
struct m0_op oc_op
M0_INTERNAL void m0_indexvec_free(struct m0_indexvec *ivec)
Definition: vec.c:553
static int pargrp_iomap_replica_elect(struct pargrp_iomap *map)
Definition: io_pargrp.c:2112
M0_INTERNAL void m0_free_aligned(void *data, size_t size, unsigned shift)
Definition: memory.c:192
uint64_t m0_bindex_t
Definition: types.h:80
uint64_t ti_obj
bool ioo_rect_needed
M0_INTERNAL void * m0_bufvec_cursor_addr(struct m0_bufvec_cursor *cur)
Definition: vec.c:597
uint64_t m0_bcount_t
Definition: types.h:77
M0_INTERNAL int m0_poolmach_device_state(struct m0_poolmach *pm, uint32_t device_index, enum m0_pool_nd_state *state_out)
Definition: pool_machine.c:816
M0_INTERNAL int m0_parity_math_recover(struct m0_parity_math *math, struct m0_buf *data, struct m0_buf *parity, struct m0_buf *fails, enum m0_parity_linsys_algo algo)
Definition: parity_math.c:383
static int void * buf
Definition: dir.c:1019
static uint64_t round_up(uint64_t val, uint64_t size)
Definition: file.c:711
M0_INTERNAL bool pargrp_iomap_invariant(const struct pargrp_iomap *map)
Definition: io_pargrp.c:203
M0_INTERNAL int m0_parity_math_diff(struct m0_parity_math *math, struct m0_buf *old, struct m0_buf *new, struct m0_buf *parity, uint32_t index)
Definition: parity_math.c:371
M0_INTERNAL bool m0__is_update_op(struct m0_op *op)
Definition: utils.c:290
static struct data_buf * data_buf_alloc_init(struct m0_obj *obj, enum page_attr pattr)
Definition: io_pargrp.c:323
M0_INTERNAL const struct m0_key_val M0_KEY_VAL_NULL
Definition: misc.c:358
static const struct pargrp_iomap_ops iomap_ops
Definition: io_pargrp.c:2334
M0_INTERNAL bool m0_ivec_cursor_move_to(struct m0_ivec_cursor *cur, m0_bindex_t dest)
Definition: vec.c:745
M0_INTERNAL void pargrp_iomap_fini(struct pargrp_iomap *map, struct m0_obj *obj)
Definition: io_pargrp.c:2467
static struct foo * obj
Definition: tlist.c:302
const char * bt_name
Definition: bob.h:73
Definition: sock.c:887
static m0_bcount_t count
Definition: xcode.c:167
static bool pargrp_iomap_spans_seg(struct pargrp_iomap *map, m0_bindex_t index, m0_bcount_t count)
Definition: io_pargrp.c:728
M0_INTERNAL uint64_t m0_round_up(uint64_t val, uint64_t size)
Definition: misc.c:181
static int io_spare_map(const struct pargrp_iomap *map, const struct m0_pdclust_src_addr *src, uint32_t *spare_slot, uint32_t *spare_slot_prev, enum m0_pool_nd_state *eff_state)
Definition: io_pargrp.c:1580
#define SEG_NR(ivec)
Definition: file.c:393
return M0_RC(rc)
op
Definition: libdemo.c:64
unsigned int op_code
Definition: client.h:650
M0_INTERNAL void m0_parity_math_calculate(struct m0_parity_math *math, struct m0_buf *data, struct m0_buf *parity)
Definition: parity_math.c:362
static struct data_buf * data_buf_replicate_init(struct pargrp_iomap *map, int row, enum page_attr pattr)
Definition: io_pargrp.c:357
static bool crc_cmp(const struct m0_buf *val1, const struct m0_buf *val2)
Definition: io_pargrp.c:2086
static uint32_t unit_size
Definition: layout.c:53
M0_INTERNAL bool pargrp_iomap_invariant_nr(const struct m0_op_io *ioo)
Definition: io_pargrp.c:227
#define M0_ENTRY(...)
Definition: trace.h:170
Definition: buf.h:37
M0_INTERNAL bool m0_bufvec_cursor_move(struct m0_bufvec_cursor *cur, m0_bcount_t count)
Definition: vec.c:574
static char * addr
Definition: node_k.c:37
static void pargrp_iomap_bufs_free(struct data_buf ***bufs, int nr)
Definition: io_pargrp.c:2353
static m0_bindex_t gobj_offset(m0_bindex_t toff, struct pargrp_iomap *map, struct m0_pdclust_layout *play, struct m0_pdclust_src_addr *src)
Definition: io_pargrp.c:115
int i
Definition: dir.c:1033
m0_pdclust_unit_type
Definition: pdclust.h:89
enum page_attr db_flags
#define PRIu64
Definition: types.h:58
Definition: client.h:641
static uint32_t rows_nr(struct m0_pdclust_layout *play)
Definition: file.c:691
#define M0_ERR_INFO(rc, fmt,...)
Definition: trace.h:215
return M0_ERR(-EOPNOTSUPP)
static void db_crc_set(struct data_buf *dbuf, uint32_t key, struct m0_key_val *kv)
Definition: io_pargrp.c:2091
struct m0_op_obj ioo_oo
M0_INTERNAL struct m0_poolmach * ioo_to_poolmach(struct m0_op_io *ioo)
Definition: io.c:75
void * b_addr
Definition: buf.h:231
M0_INTERNAL struct m0_client * m0__op_instance(const struct m0_op *op)
Definition: client.c:236
static int key
Definition: locality.c:283
int(* pi_populate)(struct pargrp_iomap *iomap, struct m0_ivec_varr_cursor *cursor)
#define m0_free0(pptr)
Definition: memory.h:77
static uint64_t page_nr(m0_bcount_t size)
Definition: file.c:492
m0_bcount_t b_nob
Definition: buf.h:38
#define M0_ASSERT(cond)
static void seg_idx_inc_round(struct pargrp_iomap *map, uint32_t seg, uint64_t sz)
Definition: io_pargrp.c:404
struct m0_buf db_buf
static void data_buf_init(struct data_buf *buf, void *addr, uint64_t addr_size, uint64_t flags)
Definition: io_pargrp.c:246
M0_INTERNAL void m0_crc32(const void *data, uint64_t len, uint64_t *cksum)
Definition: crc.c:83
uint64_t db_crc
Definition: pg.h:209
M0_INTERNAL void m0_key_val_init(struct m0_key_val *kv, const struct m0_buf *key, const struct m0_buf *val)
Definition: misc.c:369
M0_INTERNAL uint64_t pargrp_id_find(m0_bindex_t index, const struct m0_op_io *ioo, const struct ioreq_fop *ir_fop)
Definition: io_pargrp.c:105
m0_pool_nd_state
Definition: pool_machine.h:57
static struct m0_pdclust_instance * pdlayout_instance(const struct m0_layout_instance *li)
Definition: file.c:504
uint64_t ta_frame
Definition: pdclust.h:254
static void pargrp_src_addr(m0_bindex_t index, const struct m0_op_io *ioo, const struct target_ioreq *tio_req, struct m0_pdclust_src_addr *src)
Definition: io_pargrp.c:84
struct m0_obj * ioo_obj
enum m0_pbuf_type ioo_pbuf_type
static uint64_t layout_unit_size(const struct m0_pdclust_layout *play)
Definition: file.c:525
static int pargrp_iomap_pages_mark_as_failed(struct pargrp_iomap *map, enum m0_pdclust_unit_type type)
Definition: io_pargrp.c:1457
void * m0_alloc(size_t size)
Definition: memory.c:126
static int pargrp_iomap_parity_verify(struct pargrp_iomap *map)
Definition: io_pargrp.c:2231
static int pargrp_iomap_dgmode_postprocess(struct pargrp_iomap *map)
Definition: io_pargrp.c:1822
#define M0_POST(cond)
Definition: xcode.h:73
struct m0_fid oo_fid
const struct m0_bob_type pgiomap_bobtype
Definition: io_pargrp.c:54
static int pargrp_iomap_populate_pi_ivec(struct pargrp_iomap *map, struct m0_ivec_cursor *cursor, struct m0_bufvec_cursor *buf_cursor, bool rmw)
Definition: io_pargrp.c:427
static m0_bindex_t offset
Definition: dump.c:173
static int pargrp_iomap_readold_auxbuf_alloc(struct pargrp_iomap *map)
Definition: io_pargrp.c:962
M0_INTERNAL void m0_fd_bwd_map(struct m0_pdclust_instance *pi, const struct m0_pdclust_tgt_addr *tgt, struct m0_pdclust_src_addr *src)
Definition: fd.c:959
M0_INTERNAL void m0_buf_free(struct m0_buf *buf)
Definition: buf.c:55
static uint64_t min64u(uint64_t a, uint64_t b)
Definition: arith.h:66
M0_INTERNAL bool m0_ivec_cursor_move(struct m0_ivec_cursor *cur, m0_bcount_t count)
Definition: vec.c:718
struct m0_op_common oo_oc
static void page_pos_get(struct pargrp_iomap *map, m0_bindex_t index, uint32_t *row, uint32_t *col)
Definition: file.c:725
static void data_buf_fini(struct data_buf *buf)
Definition: io_pargrp.c:272
static uint64_t data_size(const struct m0_pdclust_layout *play)
Definition: file.c:550
M0_INTERNAL bool addr_is_network_aligned(void *addr)
Definition: utils.c:29
M0_INTERNAL m0_bcount_t m0_vec_count(const struct m0_vec *vec)
Definition: vec.c:53
static uint64_t round_down(uint64_t val, uint64_t size)
Definition: file.c:697
static uint32_t layout_n(const struct m0_pdclust_layout *play)
Definition: file.c:515
static struct m0_pdclust_layout * pdlayout_get(const struct io_request *req)
Definition: file.c:510
static bool are_pbufs_allocated(struct m0_op_io *ioo)
Definition: io_pargrp.c:2458
#define m0_forall(var, nr,...)
Definition: misc.h:112
uint64_t sa_unit
Definition: pdclust.h:243
#define PRIu32
Definition: types.h:66
static size_t offset_get(struct pargrp_iomap *map)
Definition: io_pargrp.c:2101
struct m0_pdclust_tgt_addr tgt
Definition: fd.c:110
static uint8_t fail[DATA_UNIT_COUNT_MAX+PARITY_UNIT_COUNT_MAX]
static struct m0_parity_math * parity_math(struct io_request *req)
Definition: file.c:555
static int pargrp_iomap_bufs_alloc(struct data_buf ****bufs_out, uint32_t row_nr, uint32_t col_nr)
Definition: io_pargrp.c:2362
struct target_ioreq * irf_tioreq
Definition: pg.h:881
#define M0_BUF_INIT_PTR(p)
Definition: buf.h:69
static int pargrp_iomap_select_ro_rr(struct pargrp_iomap *map, m0_bcount_t data_pages_nr, m0_bcount_t parity_pages_nr)
Definition: io_pargrp.c:533
#define M0_FI_ENABLED(tag)
Definition: finject.h:231
Definition: fid.h:38
static struct m0_layout_instance * layout_instance(const struct io_request *req)
Definition: file.c:498
static int pargrp_iomap_databuf_alloc(struct pargrp_iomap *map, uint32_t row, uint32_t col, struct m0_bufvec_cursor *data)
Definition: io_pargrp.c:877
#define M0_ALLOC_PTR(ptr)
Definition: memory.h:86
static int pargrp_iomap_dgmode_recover(struct pargrp_iomap *map)
Definition: io_pargrp.c:1985
static int64_t min64(int64_t a, int64_t b)
Definition: arith.h:46
static int pargrp_iomap_paritybufs_alloc(struct pargrp_iomap *map)
Definition: io_pargrp.c:1296
static int unit_state(const struct m0_pdclust_src_addr *src, struct m0_op_io *ioo, enum m0_pool_nd_state *state)
Definition: io_pargrp.c:1541
static uint32_t iomap_dgmode_recov_prepare(struct pargrp_iomap *map, uint8_t *failed)
Definition: io_pargrp.c:1949
M0_INTERNAL uint64_t obj_buffer_size(const struct m0_obj *obj)
Definition: utils.c:34
m0_bcount_t size
Definition: di.c:39
static uint64_t parity_units_page_nr(const struct m0_pdclust_layout *play)
Definition: file.c:530
page_attr
static m0_bindex_t seg_set(struct pargrp_iomap *map, uint32_t seg, struct m0_ivec_cursor *cur, m0_bindex_t grpend)
Definition: io_pargrp.c:392
static int start(struct m0_fom *fom)
Definition: trigger_fom.c:321
M0_INTERNAL m0_bindex_t m0_ivec_cursor_index(const struct m0_ivec_cursor *cur)
Definition: vec.c:733
static struct m0 instance
Definition: main.c:78
static int pargrp_iomap_seg_process(struct pargrp_iomap *map, uint32_t seg, bool rmw, uint64_t skip_buf_index, struct m0_bufvec_cursor *buf_cursor)
Definition: io_pargrp.c:755
M0_INTERNAL struct m0_client * m0__obj_instance(const struct m0_obj *obj)
Definition: client.c:261
static struct m0_be_seg * seg
Definition: btree.c:40
static uint64_t pargrp_iomap_auxbuf_alloc(struct pargrp_iomap *map, uint32_t row, uint32_t col)
Definition: io_pargrp.c:931
uint64_t ioo_iomap_nr
M0_INTERNAL void * m0_vote_majority_get(struct m0_key_val *arr, uint32_t len, bool(*cmp)(const struct m0_buf *, const struct m0_buf *), uint32_t *vote_nr)
Definition: misc.c:383
M0_INTERNAL uint64_t m0__page_size(const struct m0_op_io *ioo)
Definition: utils.c:41
static void seg_align(struct pargrp_iomap *map, uint32_t seg, m0_bindex_t end, uint64_t sz)
Definition: io_pargrp.c:414
int type
Definition: dir.c:1031
static void data_buf_dealloc_fini(struct data_buf *buf)
Definition: io_pargrp.c:290
struct m0_fid gfid
Definition: dir.c:626
M0_INTERNAL void * m0_alloc_aligned(size_t size, unsigned shift)
Definition: memory.c:168
Definition: pg.h:859
struct target_ioreq * db_tioreq
static uint64_t iomap_page_nr(struct pargrp_iomap *map)
Definition: file.c:545
M0_INTERNAL void m0_fd_fwd_map(struct m0_pdclust_instance *pi, const struct m0_pdclust_src_addr *src, struct m0_pdclust_tgt_addr *tgt)
Definition: fd.c:838
#define M0_PRE_EX(cond)
void m0_free(void *data)
Definition: memory.c:146
struct m0_pdclust_src_addr src
Definition: fd.c:108
int32_t rc
Definition: trigger_fop.h:47
#define M0_POST_EX(cond)
#define offsetof(typ, memb)
Definition: misc.h:29
M0_INTERNAL int pargrp_iomap_init(struct pargrp_iomap *map, struct m0_op_io *ioo, uint64_t grpid)
Definition: io_pargrp.c:2387
static uint8_t parity[DATA_UNIT_COUNT_MAX][UNIT_BUFF_SIZE_MAX]
M0_INTERNAL uint64_t m0_pdclust_unit_size(const struct m0_pdclust_layout *pl)
Definition: pdclust.c:377
struct pargrp_iomap ** ioo_iomaps
static struct m0_addb2_frame_header last
Definition: storage.c:93
static int pargrp_iomap_databuf_replicate(struct pargrp_iomap *map)
Definition: io_pargrp.c:1387
Definition: trace.h:478
M0_INTERNAL bool m0_op_io_invariant(const struct m0_op_io *iop)
Definition: io.c:161
Definition: idx_mock.c:47