Motr  M0
seg.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_UT
24 #include "lib/trace.h"
25 
26 #include "be/seg.h" /* m0_be_seg */
27 
28 #include "lib/types.h" /* uint64_t */
29 #include "lib/arith.h" /* m0_rnd64 */
30 #include "lib/thread.h" /* M0_THREAD_INIT */
31 #include "lib/semaphore.h" /* m0_semaphore */
32 #include "lib/misc.h" /* m0_forall */
33 #include "lib/memory.h" /* M0_ALLOC_PTR */
34 
35 #include "ut/ut.h" /* M0_UT_ASSERT */
36 #include "ut/stob.h" /* m0_ut_stob_linux_get */
37 #include "be/ut/helper.h" /* m0_be_ut_seg_helper */
38 
39 enum {
40  BE_UT_SEG_SIZE = 0x20000,
42  BE_UT_SEG_IO_OFFS = 0x10000,
43  BE_UT_SEG_IO_SIZE = 0x10000,
44 };
46 
47 M0_INTERNAL void m0_be_ut_seg_open_close(void)
48 {
49  struct m0_be_ut_seg ut_seg;
50 
53 }
54 
55 static void be_ut_seg_rand_reg(struct m0_be_reg *reg,
56  void *seg_addr,
59  uint64_t *seed)
60 {
61  *size = m0_rnd64(seed) % (BE_UT_SEG_IO_SIZE / 2) + 1;
62  *offset = m0_rnd64(seed) % (BE_UT_SEG_IO_SIZE / 2 - 1);
63  reg->br_addr = seg_addr + BE_UT_SEG_IO_OFFS + *offset;
64  reg->br_size = *size;
65 }
66 
67 M0_INTERNAL void m0_be_ut_seg_io(void)
68 {
69  struct m0_be_ut_seg ut_seg;
70  struct m0_be_seg *seg;
71  struct m0_be_reg reg;
72  struct m0_be_reg reg_check;
75  static char pre[BE_UT_SEG_IO_SIZE];
76  static char post[BE_UT_SEG_IO_SIZE];
77  static char rand[BE_UT_SEG_IO_SIZE];
78  uint64_t seed = 0;
79  int rc;
80  int i;
81  int j;
82  int cmp;
83 
85  seg = ut_seg.bus_seg;
86  reg_check = M0_BE_REG(seg, BE_UT_SEG_IO_SIZE,
88  for (i = 0; i < BE_UT_SEG_IO_ITER; ++i) {
90  reg.br_seg = seg;
91  for (j = 0; j < reg.br_size; ++j)
92  rand[j] = m0_rnd64(&seed) & 0xFF;
93 
94  /* read segment before write operation */
95  rc = m0_be_seg__read(&reg_check, pre);
96  M0_UT_ASSERT(rc == 0);
97  /* write */
98  rc = m0_be_seg__write(&reg, rand);
99  M0_UT_ASSERT(rc == 0);
100  /* and read to check if it was written */
101  rc = m0_be_seg__read(&reg_check, post);
102  M0_UT_ASSERT(rc == 0);
103  /* reload segment to test I/O operations in open()/close() */
105  rc = m0_be_seg_open(seg);
106  M0_UT_ASSERT(rc == 0);
107 
108  for (j = 0; j < size; ++j)
109  pre[j + offset] = rand[j];
110 
111  M0_CASSERT(ARRAY_SIZE(pre) == ARRAY_SIZE(post));
112  /*
113  * check if data was written to stob
114  * just after write operation
115  */
116  cmp = memcmp(pre, post, ARRAY_SIZE(pre));
117  M0_UT_ASSERT(cmp == 0);
118  /* compare segment contents before and after reload */
119  cmp = memcmp(post, reg_check.br_addr, reg_check.br_size);
120  M0_UT_ASSERT(cmp == 0);
121  }
123 }
124 
125 enum {
129 };
130 
132 {
133  struct m0_be_ut_seg ut_seg;
134  int i;
135 
137  for (i = 0; i < BE_UT_SEG_PER_THREAD; ++i) {
140  }
141 }
142 
144 {
145  static struct m0_thread threads[BE_UT_SEG_THREAD_NR];
146  struct m0_semaphore barrier;
147  bool rc_bool;
148 
150  rc_bool = m0_forall(i, ARRAY_SIZE(threads),
151  M0_THREAD_INIT(&threads[i], struct m0_semaphore *,
153  &barrier, "#%dbe-seg-ut", i) == 0);
154  M0_UT_ASSERT(rc_bool);
155  m0_forall(i, ARRAY_SIZE(threads), m0_semaphore_up(&barrier), true);
156  rc_bool = m0_forall(i, ARRAY_SIZE(threads),
157  m0_thread_join(&threads[i]) == 0);
158  M0_UT_ASSERT(rc_bool);
159  m0_forall(i, ARRAY_SIZE(threads), m0_thread_fini(&threads[i]), true);
161 }
162 
163 /*
164  * How to test really large segment:
165  * 1. Select segment size you want to test:
166  * 1.a Set BE_UT_SEG_LARGE_SIZE to the needed value.
167  * 1.b Machine should have at least BE_UT_SEG_LARGE_SIZE virtual memory
168  * available (RAM + swap). Use dd to some file (or just use disk or
169  * partititon) + mkswap + swapon to add virtual memory if needed.
170  * 2. Change "stob = " at the beginning of m0_be_ut_seg_large() to point to
171  * some large file that will be used as backing store. You can skip this
172  * step if the filesystem with "ut-sandbox" has enough free space.
173  * 3. Run the test. It will take some time. Use iostat, vmstat, blktrace,
174  * iotop or dstat to check if I/O actually happens.
175  */
176 enum {
177  /*
178  * It should be > 4GiB, but devvm with small memory will have
179  * a problem with this UT. So it is set to a small value.
180  * It may be increased after paged implemented.
181  */
182  BE_UT_SEG_LARGE_SIZE = 1ULL << 27, /* 128 MiB */
183  /* BE_UT_SEG_LARGE_SIZE = 1ULL << 34, */ /* 16 GiB */
184  /* Each step-th byte will be overwritten in the test. */
186  /* Block size for stob I/O in the test */
188 };
189 
190 static void be_ut_seg_large_mem(struct m0_be_seg *seg,
191  char byte,
193  bool check)
194 {
195  m0_bindex_t i;
196  char *addr = seg->bs_addr;
197 
198  for (i = 0; i < size; i += BE_UT_SEG_LARGE_STEP) {
199  if (i < seg->bs_reserved)
200  continue;
201  if (check)
202  M0_UT_ASSERT(addr[i] == byte);
203  else
204  addr[i] = byte;
205  }
206 }
207 
210  m0_bcount_t block_size,
211  char *block,
212  bool read)
213 {
214  struct m0_be_reg reg;
215 
216  reg = M0_BE_REG(seg, block_size, seg->bs_addr + offset);
217  if (read)
218  m0_be_seg__read(&reg, block);
219  else
220  m0_be_seg__write(&reg, block);
221 }
222 
223 /*
224  * Checks bytes of backing storage with step or writes bytes with some step
225  * to the backing storage.
226  *
227  * @note It does RMW in "write" case. UT with large (~16GB) segment will take
228  * a very long time (estimated ~1h on devvm with SSD).
229  */
230 static void be_ut_seg_large_stob(struct m0_be_seg *seg,
231  char byte,
233  bool check)
234 {
235  m0_bindex_t i;
236  m0_bindex_t block_begin = M0_BINDEX_MAX;
237  m0_bindex_t block_begin_new;
239  m0_bcount_t size_left = 0;
240  char *block;
241 
242  block = m0_alloc(block_size);
243  M0_UT_ASSERT(block != NULL);
244  for (i = 0; i < size; i += BE_UT_SEG_LARGE_STEP) {
245  if (i < seg->bs_reserved)
246  continue;
247  /* Do block I/O if block was changed after previous I/O. */
248  block_begin_new = m0_round_down(i, block_size);
249  size_left = min_check(block_size, size - block_begin_new);
250  if (block_begin_new != block_begin) {
251  if (!check && block_begin != M0_BINDEX_MAX) {
252  /* W from RMW is here */
253  be_ut_seg_large_block_io(seg, block_begin,
254  block_size, block,
255  false);
256  }
257  be_ut_seg_large_block_io(seg, block_begin_new,
258  size_left, block, true);
259  block_begin = block_begin_new;
260  }
261  if (check) {
262  M0_UT_ASSERT(block[i - block_begin] == byte);
263  } else {
264  block[i - block_begin] = byte;
265  }
266  }
267  /* last W from RMW is here */
268  if (size_left > 0) {
269  be_ut_seg_large_block_io(seg, block_begin, size_left,
270  block, false);
271  }
272  m0_free(block);
273 }
274 
276 {
277  struct m0_be_seg *seg;
278  struct m0_stob *stob;
280  void *addr;
281  int rc;
282 
283  M0_ALLOC_PTR(seg);
284  M0_UT_ASSERT(seg != NULL);
286  /* stob = m0_ut_stob_linux_create("/dev/sdc1"); */
287  M0_UT_ASSERT(stob != NULL);
288 
291 
294  M0_UT_ASSERT(rc == 0);
295  rc = m0_be_seg_open(seg);
296  M0_UT_ASSERT(rc == 0);
297 
298  M0_LOG(M0_DEBUG, "check if in-memory segment data is initially zeroed");
299  be_ut_seg_large_mem(seg, 0, size, true);
300  M0_LOG(M0_DEBUG, "check if backing store is initially zeroed");
301  be_ut_seg_large_stob(seg, 0, size, true);
302  M0_LOG(M0_DEBUG, "write 1 to in-memory segment data");
303  be_ut_seg_large_mem(seg, 1, size, false);
304  M0_LOG(M0_DEBUG, "check 1 in in-memory segment data");
305  be_ut_seg_large_mem(seg, 1, size, true);
306  M0_LOG(M0_DEBUG, "check if backing store is still zeroed");
307  be_ut_seg_large_stob(seg, 0, size, true);
308  M0_LOG(M0_DEBUG, "write 2 to the backing store");
309  be_ut_seg_large_stob(seg, 2, size, false);
310  M0_LOG(M0_DEBUG, "check 1 in in-memory segment data");
311  be_ut_seg_large_mem(seg, 1, size, true);
312  M0_LOG(M0_DEBUG, "check 2 in the backing store");
313  be_ut_seg_large_stob(seg, 2, size, true);
314  M0_LOG(M0_DEBUG, "write 3 to in-memory segment data");
315  be_ut_seg_large_mem(seg, 3, size, false);
316  M0_LOG(M0_DEBUG, "check 3 in in-memory segment data");
317  be_ut_seg_large_mem(seg, 3, size, true);
318  M0_LOG(M0_DEBUG, "check 2 in the backing store");
319  be_ut_seg_large_stob(seg, 2, size, true);
320 
323  M0_UT_ASSERT(rc == 0);
325 
326  m0_ut_stob_put(stob, true);
327  m0_free(seg);
328 }
329 
331 {
332  struct m0_be_seg_geom geom[] = {
333  {
334  .sg_size = 0ULL,
335  .sg_addr = NULL,
336  .sg_offset = 0ULL,
337  .sg_id = 1,
338  },
339  {
340  .sg_size = 0ULL,
341  .sg_addr = NULL,
342  .sg_offset = 0ULL,
343  .sg_id = 1,
344  },
345  {
346  .sg_size = 0ULL,
347  .sg_addr = NULL,
348  .sg_offset = 0ULL,
349  .sg_id = 1,
350  },
352  };
353  int i;
355  m0_bcount_t offset = 0;
356  void *addr;
357  int rc;
358  struct m0_be_seg *seg[ARRAY_SIZE(geom) - 1];
359  struct m0_stob *stob;
360 
362 
363  for (i = 0; !m0_be_seg_geom_eq(&geom[i], &M0_BE_SEG_GEOM0); ++i) {
365  geom[i] = (struct m0_be_seg_geom) {
366  .sg_size = size,
367  .sg_addr = addr,
368  .sg_offset = offset,
369  .sg_id = i+0x111,
370  },
371  offset += size;
372  }
373 
375  M0_UT_ASSERT(stob != NULL);
377  M0_UT_ASSERT(rc == 0);
378 
379  for (i = 0; i < ARRAY_SIZE(geom) - 1; ++i) {
380  M0_ALLOC_PTR(seg[i]);
381  M0_UT_ASSERT(seg[i] != NULL);
382  m0_be_seg_init(seg[i], stob, NULL, geom[i].sg_id);
383  M0_UT_ASSERT(rc == 0);
384  rc = m0_be_seg_open(seg[i]);
385  M0_UT_ASSERT(rc == 0);
386  }
387 
388  for (i = 0; i < ARRAY_SIZE(geom) - 1; ++i) {
389  M0_LOG(M0_DEBUG, "check if in-memory segment data is initially"
390  " zeroed");
391  be_ut_seg_large_mem(seg[i], 0, size, true);
392  M0_LOG(M0_DEBUG, "check if backing store is initially zeroed");
393  be_ut_seg_large_stob(seg[i], 0, size, true);
394  M0_LOG(M0_DEBUG, "write 1 to in-memory segment data");
395  be_ut_seg_large_mem(seg[i], 1, size, false);
396  M0_LOG(M0_DEBUG, "check 1 in in-memory segment data");
397  be_ut_seg_large_mem(seg[i], 1, size, true);
398  M0_LOG(M0_DEBUG, "check if backing store is still zeroed");
399  be_ut_seg_large_stob(seg[i], 0, size, true);
400  M0_LOG(M0_DEBUG, "write 2 to the backing store");
401  be_ut_seg_large_stob(seg[i], 2, size, false);
402  M0_LOG(M0_DEBUG, "check 1 in in-memory segment data");
403  be_ut_seg_large_mem(seg[i], 1, size, true);
404  M0_LOG(M0_DEBUG, "check 2 in the backing store");
405  be_ut_seg_large_stob(seg[i], 2, size, true);
406  M0_LOG(M0_DEBUG, "write 3 to in-memory segment data");
407  be_ut_seg_large_mem(seg[i], 3, size, false);
408  M0_LOG(M0_DEBUG, "check 3 in in-memory segment data");
409  be_ut_seg_large_mem(seg[i], 3, size, true);
410  M0_LOG(M0_DEBUG, "check 2 in the backing store");
411  be_ut_seg_large_stob(seg[i], 2, size, true);
412  }
413 
414  for (i = 0; i < ARRAY_SIZE(geom) - 1; ++i) {
417  M0_UT_ASSERT(rc == 0);
418  m0_be_seg_fini(seg[i]);
419  m0_free(seg[i]);
420  }
421 
422  m0_ut_stob_put(stob, true);
423 }
424 
425 #undef M0_TRACE_SUBSYSTEM
426 
427 /*
428  * Local variables:
429  * c-indentation-style: "K&R"
430  * c-basic-offset: 8
431  * tab-width: 8
432  * fill-column: 80
433  * scroll-step: 1
434  * End:
435  */
436 /*
437  * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap
438  */
void m0_be_ut_seg_multiple(void)
Definition: seg.c:143
void * bs_addr
Definition: seg.h:71
M0_INTERNAL int m0_be_seg__write(struct m0_be_reg *reg, void *src)
Definition: seg.c:452
void m0_be_ut_seg_fini(struct m0_be_ut_seg *ut_seg)
Definition: stubs.c:267
static void be_ut_seg_rand_reg(struct m0_be_reg *reg, void *seg_addr, m0_bindex_t *offset, m0_bcount_t *size, uint64_t *seed)
Definition: seg.c:55
M0_INTERNAL void m0_be_seg_fini(struct m0_be_seg *seg)
Definition: seg.c:275
#define NULL
Definition: misc.h:38
M0_INTERNAL int m0_be_seg_create_multiple(struct m0_stob *stob, const struct m0_be_seg_geom *geom)
Definition: seg.c:195
int m0_thread_join(struct m0_thread *q)
Definition: kthread.c:169
M0_INTERNAL void m0_be_ut_seg_io(void)
Definition: seg.c:67
#define M0_LOG(level,...)
Definition: trace.h:167
#define min_check(a, b)
Definition: arith.h:88
M0_INTERNAL void * m0_be_ut_seg_allocate_addr(m0_bcount_t size)
Definition: helper.c:107
#define M0_CASSERT(cond)
struct m0_be_seg * bus_seg
Definition: helper.h:119
M0_INTERNAL int m0_be_seg_create(struct m0_be_seg *seg, m0_bcount_t size, void *addr)
Definition: seg.c:224
m0_bcount_t br_size
Definition: seg.h:144
M0_INTERNAL void m0_be_ut_seg_open_close(void)
Definition: seg.c:47
uint64_t m0_bindex_t
Definition: types.h:80
struct m0_be_ut_seg ut_seg
Definition: ad.c:73
void m0_be_ut_seg_init(struct m0_be_ut_seg *ut_seg, struct m0_be_ut_backend *ut_be, m0_bcount_t size)
Definition: stubs.c:256
uint64_t m0_bcount_t
Definition: types.h:77
#define M0_THREAD_INIT(thread, TYPE, init, func, arg, namefmt,...)
Definition: thread.h:139
static void be_ut_seg_large_stob(struct m0_be_seg *seg, char byte, m0_bcount_t size, bool check)
Definition: seg.c:230
#define M0_BE_REG(seg, size, addr)
Definition: seg.h:148
M0_INTERNAL int m0_be_seg_open(struct m0_be_seg *seg)
Definition: seg.c:324
M0_INTERNAL uint64_t m0_round_down(uint64_t val, uint64_t size)
Definition: misc.c:187
static char * addr
Definition: node_k.c:37
int i
Definition: dir.c:1033
M0_INTERNAL struct m0_stob * m0_ut_stob_linux_get(void)
Definition: stob.c:169
Definition: stob.h:163
static struct m0_stob * stob
Definition: storage.c:39
M0_INTERNAL int m0_be_seg__read(struct m0_be_reg *reg, void *dst)
Definition: seg.c:447
M0_BASSERT(BE_UT_SEG_IO_OFFS+BE_UT_SEG_IO_SIZE<=BE_UT_SEG_SIZE)
M0_INTERNAL void m0_be_seg_close(struct m0_be_seg *seg)
Definition: seg.c:394
int rand(void)
void m0_thread_fini(struct m0_thread *q)
Definition: thread.c:92
static int cmp(const struct m0_ut_suite **s0, const struct m0_ut_suite **s1)
Definition: ut.c:654
M0_INTERNAL int m0_semaphore_init(struct m0_semaphore *semaphore, unsigned value)
Definition: semaphore.c:38
void * m0_alloc(size_t size)
Definition: memory.c:126
Definition: xcode.h:73
static m0_bindex_t offset
Definition: dump.c:173
Definition: seg.h:66
Definition: seg.h:142
M0_INTERNAL void m0_ut_stob_put(struct m0_stob *stob, bool destroy)
Definition: stob.c:185
M0_INTERNAL void m0_be_seg_init(struct m0_be_seg *seg, struct m0_stob *stob, struct m0_be_domain *dom, uint64_t seg_id)
Definition: seg.c:253
void m0_be_ut_seg_large_multiple(void)
Definition: seg.c:330
uint64_t sg_id
Definition: seg.h:488
#define M0_BE_SEG_GEOM0
Definition: seg.h:100
#define m0_forall(var, nr,...)
Definition: misc.h:112
static void be_ut_seg_thread_func(struct m0_semaphore *barrier)
Definition: seg.c:131
m0_bcount_t sg_size
Definition: seg.h:90
void m0_be_ut_seg_large(void)
Definition: seg.c:275
M0_INTERNAL uint64_t m0_rnd64(uint64_t *seed)
Definition: misc.c:100
#define M0_ALLOC_PTR(ptr)
Definition: memory.h:86
M0_INTERNAL void m0_semaphore_fini(struct m0_semaphore *semaphore)
Definition: semaphore.c:45
static void be_ut_seg_large_mem(struct m0_be_seg *seg, char byte, m0_bcount_t size, bool check)
Definition: seg.c:190
M0_INTERNAL int m0_be_seg_destroy(struct m0_be_seg *seg)
Definition: seg.c:243
m0_bcount_t size
Definition: di.c:39
M0_INTERNAL bool m0_be_seg_geom_eq(const struct m0_be_seg_geom *left, const struct m0_be_seg_geom *right)
Definition: seg.c:150
static int barrier(struct m0_buf *in, struct m0_buf *out, struct m0_isc_comp_private *comp_data, int *rc)
Definition: service_ut.c:288
static struct m0_be_seg * seg
Definition: btree.c:40
void check(struct workload *w)
static void be_ut_seg_large_block_io(struct m0_be_seg *seg, m0_bindex_t offset, m0_bcount_t block_size, char *block, bool read)
Definition: seg.c:208
M0_INTERNAL void m0_semaphore_down(struct m0_semaphore *semaphore)
Definition: semaphore.c:49
M0_INTERNAL void m0_semaphore_up(struct m0_semaphore *semaphore)
Definition: semaphore.c:65
void m0_free(void *data)
Definition: memory.c:146
struct m0_be_seg * br_seg
Definition: seg.h:143
void * br_addr
Definition: seg.h:145
int32_t rc
Definition: trigger_fop.h:47
#define ARRAY_SIZE(a)
Definition: misc.h:45
#define M0_UT_ASSERT(a)
Definition: ut.h:46