Motr  M0
lcredits.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 #include "lib/types.h" /* uint64_t */
23 #include "lib/chan.h"
24 #include "lib/misc.h"
25 #include "ut/ut.h"
26 #include "lib/ub.h"
27 
28 #include "rm/rm.h"
29 #include "rm/rm_internal.h" /* pi_tlist_length */
30 #include "rm/ut/rings.h"
31 
32 static struct m0_chan complete_chan;
33 static struct m0_chan conflict_chan;
34 static struct m0_mutex conflict_mutex;
35 
36 extern bool res_tlist_contains(const struct m0_tl *list,
37  const struct m0_rm_resource *res);
38 
39 static void lcredits_in_complete(struct m0_rm_incoming *in, int32_t rc)
40 {
41  M0_UT_ASSERT(in != NULL);
43 }
44 
45 static void lcredits_in_conflict(struct m0_rm_incoming *in)
46 {
47  M0_UT_ASSERT(in != NULL);
49 }
50 
53  .rio_conflict = lcredits_in_conflict
54 };
55 
56 static void local_credits_init(void)
57 {
66 }
67 
68 static void local_credits_fini(void)
69 {
74 }
75 
77 {
78  struct m0_rm_incoming next_in;
79 
80  /*
81  * Test verifies that no excessive credits are pinned if several
82  * cached/held credits fully satisfies incoming request by their own.
83  *
84  * The situation is simulated when owner has C0, C1 credits both fully
85  * satisfying incoming request for credit C2.
86  * Owner: Held->[C1], Cached->[C0]
87  * in->rin_want: C2
88  * diff(C2,C1) == 0 and diff(C2,C0) == 0
89  *
90  * Test checks that only one credit is used to satisfy incoming request.
91  */
92 
93  /* Move one cached credit to held list */
101 
102  /* Ask for new credit and test number of pinned credits */
103  M0_SET0(&next_in);
106  next_in.rin_want.cr_datum = ANY_RING;
107  next_in.rin_ops = &rings_incoming_ops;
108 
109  m0_rm_credit_get(&next_in);
110  M0_UT_ASSERT(next_in.rin_rc == 0);
112  M0_UT_ASSERT(pi_tlist_length(&next_in.rin_pins) == 1);
113 
115  m0_rm_credit_put(&next_in);
116 
118  m0_rm_incoming_fini(&next_in);
119 }
120 
122 {
123  struct m0_rm_incoming next_in;
124 
127 
130  /*
131  * 1. Test obtaining cached credit.
132  */
136 
137  M0_SET0(&next_in);
140  next_in.rin_want.cr_datum = VILYA;
141  next_in.rin_ops = &rings_incoming_ops;
142 
143  /*
144  * 2. Test obtaining another cached credit.
145  */
146  m0_rm_credit_get(&next_in);
147  M0_UT_ASSERT(next_in.rin_rc == 0);
149 
151  m0_rm_credit_put(&next_in);
152 
154  m0_rm_incoming_fini(&next_in);
155 }
156 
158 {
159  struct m0_rm_incoming next_in;
160  struct m0_clink clink;
161 
165 
168 
172 
173  M0_SET0(&next_in);
176  next_in.rin_want.cr_datum = NENYA;
177  next_in.rin_ops = &lcredits_incoming_ops;
178 
179  /*
180  * 1. Try to obtain conflicting held credit.
181  */
182  m0_rm_credit_get(&next_in);
183  M0_UT_ASSERT(ergo(flags == 0,
184  next_in.rin_sm.sm_state == RI_SUCCESS &&
185  next_in.rin_rc == 0));
187  next_in.rin_sm.sm_state == RI_WAIT));
189  next_in.rin_sm.sm_state == RI_FAILURE));
190 
191  if (flags & RIF_LOCAL_WAIT) {
194  }
195 
196  /* First caller releases the credit */
198 
199  /*
200  * 2. If the flag is RIF_LOCAL_WAIT, check if we get the credit
201  * after the first caller releases it.
202  */
203  if (flags & RIF_LOCAL_WAIT) {
205  M0_UT_ASSERT(next_in.rin_rc == 0);
207  m0_rm_credit_put(&next_in);
210  } else if (flags == 0 || !(flags & RIF_LOCAL_TRY)) {
211  m0_rm_credit_put(&next_in);
212  }
213 
215  m0_rm_incoming_fini(&next_in);
216 }
217 
219 {
220  struct m0_rm_incoming any_in;
221 
225 
228 
232 
233  M0_SET0(&any_in);
236  any_in.rin_want.cr_datum = ANY_RING;
237  any_in.rin_ops = &lcredits_incoming_ops;
238 
239  /*
240  * Try to obtain non-conflicting held credit.
241  */
242  m0_rm_credit_get(&any_in);
243  M0_UT_ASSERT(any_in.rin_rc == 0);
245 
247  m0_rm_credit_put(&any_in);
248 
250  m0_rm_incoming_fini(&any_in);
251 
252 }
253 
254 static void failures_test(void)
255 {
258 
261 
262  /*
263  * 1. Test - m0_rm_credit_get() with invalid credit (value) fails.
264  */
268 
269  /*
270  * 2. Test - credit_get fails when owner is not in ROS_ACTIVE state.
271  */
281 }
282 
285 {
286  struct m0_rm_incoming in1;
287  struct m0_rm_incoming in2;
288  struct m0_clink complete_clink;
289  struct m0_clink conflict_clink;
290 
291  /*
292  * Test checks that if local credits pinned with M0_RPF_BARRIER are
293  * suitable for incoming request, then incoming request is set to
294  * RI_WAIT state until these credits are unpinned. The only exception is
295  * incoming request with RIF_LOCAL_TRY flag. In that case -EBUSY is
296  * returned immediately.
297  */
298  m0_clink_init(&complete_clink, NULL);
299  m0_clink_add_lock(&complete_chan, &complete_clink);
300  m0_clink_init(&conflict_clink, NULL);
301  m0_clink_add_lock(&conflict_chan, &conflict_clink);
302 
303  /* Hold NENYA */
305  M0_RIT_LOCAL, RIP_NONE, 0);
309  m0_chan_wait(&complete_clink);
312 
313  /*
314  * Get credits with RIF_RESERVE flag. Since NENYA is already
315  * held and RIF_LOCAL_WAIT is set, request is not satisfied immediately,
316  * but requested credits are pinned with M0_RPF_BARRIER.
317  */
318  M0_SET0(&in1);
321  in1.rin_want.cr_datum = NARYA | NENYA;
323  m0_rm_credit_get(&in1);
324  M0_UT_ASSERT(in1.rin_rc == 0);
326 
327  /*
328  * Get credit pinned with M0_RPF_BARRIER.
329  * Request can't be satisfied immediately.
330  */
331  M0_SET0(&in2);
334  in2.rin_want.cr_datum = (type == OWOS_CACHED) ? NARYA : NENYA;
336  m0_rm_credit_get(&in2);
337  if (flags & RIF_LOCAL_TRY)
339  in2.rin_rc == -EBUSY);
340  else
342  in2.rin_rc == 0);
343 
344  /* Release NENYA credit, so in1 can be satisfied */
345  M0_UT_ASSERT(m0_chan_timedwait(&conflict_clink,
346  m0_time_from_now(10, 0)));
348  M0_UT_ASSERT(m0_chan_timedwait(&complete_clink,
349  m0_time_from_now(10, 0)));
350 
351  /* Release credits for in1, so in2 can be satisfied */
352  m0_rm_credit_put(&in1);
353  if (!(flags & RIF_LOCAL_TRY)) {
354  M0_UT_ASSERT(m0_chan_timedwait(&complete_clink,
355  m0_time_from_now(10, 0)));
356  m0_rm_credit_put(&in2);
357  }
358 
360  m0_rm_incoming_fini(&in1);
361  m0_rm_incoming_fini(&in2);
362  m0_clink_del_lock(&complete_clink);
363  m0_clink_fini(&complete_clink);
364  m0_clink_del_lock(&conflict_clink);
365  m0_clink_fini(&conflict_clink);
366 }
367 
369 {
370  struct m0_rm_incoming in1;
371  struct m0_rm_incoming in2;
372  struct m0_clink complete_clink;
373  struct m0_clink conflict_clink;
374 
375  /*
376  * Test checks that incoming requests with RIF_RESERVE flag are
377  * processed in order they are issued.
378  */
379  m0_clink_init(&complete_clink, NULL);
380  m0_clink_add_lock(&complete_chan, &complete_clink);
381  m0_clink_init(&conflict_clink, NULL);
382  m0_clink_add_lock(&conflict_chan, &conflict_clink);
383 
384  /* Hold NENYA */
386  M0_RIT_LOCAL, RIP_NONE, 0);
390  m0_chan_wait(&complete_clink);
393 
394  /* First request with RIF_RESERVE for NENYA */
395  M0_SET0(&in1);
398  in1.rin_want.cr_datum = NENYA;
400  m0_rm_credit_get(&in1);
401  M0_UT_ASSERT(in1.rin_rc == 0);
403 
404  /* Second request with RIF_RESERVE for NENYA */
405  M0_SET0(&in2);
408  in2.rin_want.cr_datum = NENYA;
410  m0_rm_credit_get(&in2);
412  M0_UT_ASSERT(in2.rin_rc == 0);
413 
414  /* Release NENYA */
415  M0_UT_ASSERT(m0_chan_timedwait(&conflict_clink,
416  m0_time_from_now(10, 0)));
418 
419  /* First request with RIF_RESERVE is satisfied */
420  M0_UT_ASSERT(m0_chan_timedwait(&complete_clink,
421  m0_time_from_now(10, 0)));
422  m0_rm_credit_put(&in1);
423 
424  /* Second request with RIF_RESERVE is satisfied */
425  M0_UT_ASSERT(m0_chan_timedwait(&complete_clink,
426  m0_time_from_now(10, 0)));
427  m0_rm_credit_put(&in2);
428 
430  m0_rm_incoming_fini(&in1);
431  m0_rm_incoming_fini(&in2);
432  m0_clink_del_lock(&complete_clink);
433  m0_clink_fini(&complete_clink);
434  m0_clink_del_lock(&conflict_clink);
435  m0_clink_fini(&conflict_clink);
436 }
437 
439 {
440  int i;
441  uint64_t flags[] = {0, RIF_LOCAL_WAIT, RIF_LOCAL_TRY, RIF_RESERVE,
444 
446  for (i = 0; i < ARRAY_SIZE(flags); i++) {
453  }
455  failures_test();
457 }
458 
459 /*
460  * Local variables:
461  * c-indentation-style: "K&R"
462  * c-basic-offset: 8
463  * tab-width: 8
464  * fill-column: 80
465  * scroll-step: 1
466  * End:
467  */
Definition: rm.h:886
M0_INTERNAL void m0_chan_wait(struct m0_clink *link)
Definition: chan.c:336
static struct m0_chan conflict_chan
Definition: lcredits.c:33
static struct m0_list list
Definition: list.c:144
M0_INTERNAL void m0_chan_broadcast_lock(struct m0_chan *chan)
Definition: chan.c:178
int const char const void size_t int flags
Definition: dir.c:328
uint64_t cr_datum
Definition: rm.h:514
#define NULL
Definition: misc.h:38
M0_INTERNAL void m0_clink_init(struct m0_clink *link, m0_chan_cb_t cb)
Definition: chan.c:201
static void lcredits_in_complete(struct m0_rm_incoming *in, int32_t rc)
Definition: lcredits.c:39
static void local_credits_init(void)
Definition: lcredits.c:56
M0_INTERNAL void m0_clink_del_lock(struct m0_clink *link)
Definition: chan.c:293
#define ergo(a, b)
Definition: misc.h:293
struct rm_ut_data rm_test_data
Definition: rmut.c:53
void(* rio_complete)(struct m0_rm_incoming *in, int32_t rc)
Definition: rm.h:1493
const m0_time_t M0_TIME_NEVER
Definition: time.c:108
m0_rm_owner_owned_state
Definition: rm.h:880
static void held_non_conflicting_test(enum m0_rm_incoming_flags flags)
Definition: lcredits.c:218
static struct m0_mutex conflict_mutex
Definition: lcredits.c:34
const struct m0_rm_incoming_ops rings_incoming_ops
Definition: rings.c:296
Definition: rmut.h:39
struct m0_rm_owner * rd_owner
Definition: rmut.h:112
struct m0_rm_resource_type * rd_rt
Definition: rmut.h:110
struct m0_rm_credit rin_want
Definition: rm.h:1450
#define M0_SET0(obj)
Definition: misc.h:64
void barrier_on_barrier_test(void)
Definition: lcredits.c:368
struct m0_rm_credit rd_credit
Definition: rmut.h:114
static void held_credits_test(enum m0_rm_incoming_flags flags)
Definition: lcredits.c:157
Definition: rings.h:41
m0_rm_incoming_flags
Definition: rm.h:1183
int i
Definition: dir.c:1033
struct m0_sm rin_sm
Definition: rm.h:1436
struct m0_sm ro_sm
Definition: rm.h:1005
static void local_credits_fini(void)
Definition: lcredits.c:68
bool res_tlist_contains(const struct m0_tl *list, const struct m0_rm_resource *res)
Definition: rings.h:38
M0_INTERNAL void m0_rm_incoming_init(struct m0_rm_incoming *in, struct m0_rm_owner *owner, enum m0_rm_incoming_type type, enum m0_rm_incoming_policy policy, uint64_t flags)
Definition: rm.c:1060
static void failures_test(void)
Definition: lcredits.c:254
static void cached_credits_test(enum m0_rm_incoming_flags flags)
Definition: lcredits.c:121
void rm_utdata_owner_windup_fini(struct rm_ut_data *data)
Definition: rmut.c:81
M0_INTERNAL void m0_chan_init(struct m0_chan *chan, struct m0_mutex *ch_guard)
Definition: chan.c:96
static void reserved_credit_get_test(enum m0_rm_incoming_flags flags, enum m0_rm_owner_owned_state type)
Definition: lcredits.c:283
static struct m0_chan complete_chan
Definition: lcredits.c:32
Definition: rm.h:828
Definition: rings.h:96
Definition: rings.h:94
static void lcredits_in_conflict(struct m0_rm_incoming *in)
Definition: lcredits.c:45
Definition: tlist.h:251
static void credits_pinned_number_test(enum m0_rm_incoming_flags flags)
Definition: lcredits.c:76
const struct m0_rm_incoming_ops * rin_ops
Definition: rm.h:1471
int32_t rin_rc
Definition: rm.h:1446
M0_INTERNAL void m0_mutex_init(struct m0_mutex *mutex)
Definition: mutex.c:35
Definition: chan.h:229
struct m0_mutex rt_lock
Definition: rm.h:404
void rm_utdata_init(struct rm_ut_data *data, enum obj_type type)
Definition: rmut.c:96
static struct m0_clink clink[RDWR_REQUEST_MAX]
Definition: rm.h:1145
Definition: rings.h:35
void m0_clink_add_lock(struct m0_chan *chan, struct m0_clink *link)
Definition: chan.c:255
M0_INTERNAL void m0_rm_credit_put(struct m0_rm_incoming *in)
Definition: rm.c:1797
M0_INTERNAL bool m0_chan_timedwait(struct m0_clink *link, const m0_time_t abs_timeout)
Definition: chan.c:349
const struct m0_rm_incoming_ops lcredits_incoming_ops
Definition: lcredits.c:51
m0_time_t m0_time_from_now(uint64_t secs, long ns)
Definition: time.c:96
void local_credits_test(void)
Definition: lcredits.c:438
M0_INTERNAL void m0_mutex_fini(struct m0_mutex *mutex)
Definition: mutex.c:42
M0_INTERNAL void m0_clink_fini(struct m0_clink *link)
Definition: chan.c:208
M0_INTERNAL void m0_rm_incoming_fini(struct m0_rm_incoming *in)
Definition: rm.c:1099
struct m0_rm_incoming rd_in
Definition: rmut.h:113
struct m0_tl rin_pins
Definition: rm.h:1466
void rings_utdata_ops_set(struct rm_ut_data *data)
Definition: rings.c:375
void rm_test_owner_capital_raise(struct m0_rm_owner *owner, struct m0_rm_credit *credit)
Definition: rmut.c:70
int type
Definition: dir.c:1031
M0_INTERNAL void m0_chan_fini_lock(struct m0_chan *chan)
Definition: chan.c:112
Definition: mutex.h:47
uint32_t sm_state
Definition: sm.h:307
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
M0_INTERNAL void m0_rm_credit_get(struct m0_rm_incoming *in)
Definition: rm.c:1758
Definition: rm.h:1156