Motr  M0
fom_long_lock.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2012-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 
29 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_FOP
30 #include "lib/trace.h"
31 #include "fop/fom_long_lock.h"
32 #include "lib/arith.h"
33 #include "lib/misc.h"
34 #include "lib/bob.h"
35 #include "motr/magic.h"
36 #include "addb2/identifier.h" /* M0_AVI_LONG_LOCK */
37 #include "addb2/addb2.h" /* M0_ADDB2_ADD */
38 
43 M0_TL_DESCR_DEFINE(m0_lll, "list of lock-links in longlock", M0_INTERNAL,
44  struct m0_long_lock_link, lll_lock_linkage, lll_magix,
46 
47 M0_TL_DEFINE(m0_lll, M0_INTERNAL, struct m0_long_lock_link);
48 
49 static const struct m0_bob_type long_lock_bob = {
50  .bt_name = "LONG_LOCK_BOB",
51  .bt_magix = M0_FOM_LL_MAGIC,
52  .bt_magix_offset = offsetof(struct m0_long_lock, l_magix)
53 };
54 
56 
59 
60 M0_INTERNAL void m0_fom_ll_global_init(void)
61 {
63 }
64 M0_EXPORTED(m0_fom_ll_global_init);
65 
66 M0_INTERNAL void m0_long_lock_link_init(struct m0_long_lock_link *link,
67  struct m0_fom *fom,
68  struct m0_long_lock_addb2 *addb2)
69 {
70  M0_PRE(fom != NULL);
71  m0_lll_tlink_init(link);
72  link->lll_fom = fom;
73  link->lll_addb2 = addb2;
74 }
75 
76 M0_INTERNAL void m0_long_lock_link_fini(struct m0_long_lock_link *link)
77 {
78  M0_PRE(!m0_lll_tlink_is_in(link));
79  link->lll_fom = NULL;
80  link->lll_addb2 = NULL;
81  m0_lll_tlink_fini(link);
82 }
83 
84 static void ll_addb2_reset(struct m0_long_lock_link *link)
85 {
86  if (link->lll_addb2 != NULL)
87  M0_SET0(link->lll_addb2);
88 }
89 
90 static void ll_addb2_post(struct m0_long_lock_link *link)
91 {
92  struct m0_long_lock_addb2 *addb2 = link->lll_addb2;
93 
94  if (addb2 != NULL)
96  (uint64_t)link->lll_fom,
97  addb2->la_wait,
98  m0_time_now() - addb2->la_taken);
99 }
100 
101 static void ll_addb2_wait_start(struct m0_long_lock_link *link)
102 {
103  if (link->lll_addb2 != NULL)
104  link->lll_addb2->la_waiting = true;
105 }
106 
107 static void ll_addb2_wait_finish(struct m0_long_lock_link *link)
108 {
109  struct m0_long_lock_addb2 *addb2 = link->lll_addb2;
110  struct m0_fom *fom = link->lll_fom;
111 
112  if (addb2 != NULL) {
113  addb2->la_taken = m0_time_now();
114  addb2->la_wait = addb2->la_waiting ?
115  addb2->la_taken - fom->fo_sm_state.sm_state_epoch : 0;
116  }
117 }
118 
119 static bool link_invariant(const struct m0_long_lock_link *link)
120 {
121  return
122  m0_long_lock_link_bob_check(link) &&
123  link->lll_fom != NULL &&
124  M0_IN(link->lll_lock_type, (M0_LONG_LOCK_READER,
126 }
127 
133 static bool lock_invariant(const struct m0_long_lock *lock)
134 {
135  struct m0_long_lock_link *last;
136  struct m0_long_lock_link *first;
137 
138  last = m0_lll_tlist_tail(&lock->l_owners);
139  first = m0_lll_tlist_head(&lock->l_waiters);
140 
141  return
142  m0_long_lock_bob_check(lock) &&
143  m0_mutex_is_locked(&lock->l_lock) &&
144  M0_IN(lock->l_state, (M0_LONG_LOCK_UNLOCKED,
147  m0_tl_forall(m0_lll, l, &lock->l_owners, link_invariant(l)) &&
148  m0_tl_forall(m0_lll, l, &lock->l_waiters, link_invariant(l)) &&
149 
150  (lock->l_state == M0_LONG_LOCK_UNLOCKED) ==
151  (m0_lll_tlist_is_empty(&lock->l_owners) &&
152  m0_lll_tlist_is_empty(&lock->l_waiters)) &&
153 
154  (lock->l_state == M0_LONG_LOCK_RD_LOCKED) ==
155  (!m0_lll_tlist_is_empty(&lock->l_owners) &&
156  m0_tl_forall(m0_lll, l, &lock->l_owners,
157  l->lll_lock_type == M0_LONG_LOCK_READER)) &&
158 
159  ergo((lock->l_state == M0_LONG_LOCK_WR_LOCKED),
160  (m0_lll_tlist_length(&lock->l_owners) == 1)) &&
161 
162  ergo(first != NULL, last != NULL) &&
163 
164  ergo(last != NULL && first != NULL,
165  ergo(last->lll_lock_type == M0_LONG_LOCK_READER,
167 }
168 
173 static bool can_lock(const struct m0_long_lock *lock,
174  const struct m0_long_lock_link *link)
175 {
176  return link->lll_lock_type == M0_LONG_LOCK_READER ?
177  lock->l_state != M0_LONG_LOCK_WR_LOCKED :
178  lock->l_state == M0_LONG_LOCK_UNLOCKED;
179 }
180 
181 static void grant(struct m0_long_lock *lock, struct m0_long_lock_link *link)
182 {
183  M0_ENTRY("lock=%p link=%p fom=%p", lock, link, link->lll_fom);
184 
185  lock->l_state = link->lll_lock_type == M0_LONG_LOCK_READER ?
187 
188  ll_addb2_wait_finish(link);
189  m0_lll_tlist_move_tail(&lock->l_owners, link);
190 }
191 
192 static bool lock(struct m0_long_lock *lock, struct m0_long_lock_link *link,
193  int next_phase)
194 {
195  bool got_lock;
196  struct m0_fom *fom;
197 
198  m0_mutex_lock(&lock->l_lock);
200  M0_PRE(!m0_lll_tlink_is_in(link));
201 
202  fom = link->lll_fom;
203  M0_PRE(fom != NULL);
204 
205  got_lock = m0_lll_tlist_is_empty(&lock->l_waiters) &&
206  can_lock(lock, link);
207  ll_addb2_reset(link);
208  if (got_lock) {
209  grant(lock, link);
210  } else {
211  ll_addb2_wait_start(link);
212  fom->fo_transitions_saved = fom->fo_transitions;
213  m0_lll_tlist_add_tail(&lock->l_waiters, link);
214  }
215  m0_fom_phase_set(fom, next_phase);
217  m0_mutex_unlock(&lock->l_lock);
218  return got_lock;
219 }
220 
221 M0_INTERNAL bool m0_long_write_lock(struct m0_long_lock *lk,
222  struct m0_long_lock_link *link,
223  int next_phase)
224 {
226  return lock(lk, link, next_phase);
227 }
228 
229 M0_INTERNAL bool m0_long_read_lock(struct m0_long_lock *lk,
230  struct m0_long_lock_link *link,
231  int next_phase)
232 {
234  return lock(lk, link, next_phase);
235 }
236 
237 M0_INTERNAL bool m0_long_lock(struct m0_long_lock *lock, bool write,
238  struct m0_long_lock_link *link,
239  int next_phase)
240 {
241  return write ? m0_long_write_lock(lock, link, next_phase) :
242  m0_long_read_lock(lock, link, next_phase);
243 }
244 
245 static void unlock(struct m0_long_lock *lock,
246  struct m0_long_lock_link *link,
247  bool check_ownership)
248 {
249  struct m0_fom *fom = link->lll_fom;
250  struct m0_long_lock_link *next;
251 
252  M0_ENTRY("lock=%p link=%p fom=%p check_ownership=%d",
253  lock, link, link->lll_fom, !!check_ownership);
254 
255  m0_mutex_lock(&lock->l_lock);
256  if (check_ownership && !m0_lll_tlist_contains(&lock->l_owners, link)) {
257  m0_mutex_unlock(&lock->l_lock);
258  return;
259  }
260 
262  M0_PRE(m0_lll_tlist_contains(&lock->l_owners, link));
264 
265  m0_lll_tlist_del(link);
266  lock->l_state =
268  m0_lll_tlist_is_empty(&lock->l_owners) ?
270  ll_addb2_post(link);
271  while ((next = m0_lll_tlist_head(&lock->l_waiters)) != NULL &&
272  can_lock(lock, next)) {
273  grant(lock, next);
274 
291  M0_ASSERT(M0_IN(next->lll_fom->fo_transitions -
292  next->lll_fom->fo_transitions_saved, (1, 0)));
293  m0_fom_wakeup(next->lll_fom);
294  }
295 
297  m0_mutex_unlock(&lock->l_lock);
298 }
299 
300 M0_INTERNAL void m0_long_write_unlock(struct m0_long_lock *lock,
301  struct m0_long_lock_link *link)
302 {
303  unlock(lock, link, false);
304 }
305 
306 M0_INTERNAL void m0_long_read_unlock(struct m0_long_lock *lock,
307  struct m0_long_lock_link *link)
308 {
309  unlock(lock, link, false);
310 }
311 
312 M0_INTERNAL void m0_long_unlock(struct m0_long_lock *lock,
313  struct m0_long_lock_link *link)
314 {
315  unlock(lock, link, true);
316 }
317 
318 M0_INTERNAL bool m0_long_is_read_locked(struct m0_long_lock *lock,
319  const struct m0_fom *fom)
320 {
321  bool ret;
322 
323  m0_mutex_lock(&lock->l_lock);
325  ret = lock->l_state == M0_LONG_LOCK_RD_LOCKED &&
326  m0_tl_exists(m0_lll, link, &lock->l_owners,
327  link->lll_fom == fom);
328  m0_mutex_unlock(&lock->l_lock);
329  return ret;
330 }
331 
332 M0_INTERNAL bool m0_long_is_write_locked(struct m0_long_lock *lock,
333  const struct m0_fom *fom)
334 {
335  bool ret;
336 
337  m0_mutex_lock(&lock->l_lock);
339 
340  ret = lock->l_state == M0_LONG_LOCK_WR_LOCKED &&
341  m0_lll_tlist_head(&lock->l_owners)->lll_fom == fom;
342 
343  m0_mutex_unlock(&lock->l_lock);
344 
345  return ret;
346 }
347 
348 M0_INTERNAL void m0_long_lock_init(struct m0_long_lock *lock)
349 {
350  m0_mutex_init(&lock->l_lock);
351 
352  m0_lll_tlist_init(&lock->l_owners);
353  m0_lll_tlist_init(&lock->l_waiters);
354 
355  lock->l_state = M0_LONG_LOCK_UNLOCKED;
356 
357  m0_long_lock_bob_init(lock);
358 }
359 
360 M0_INTERNAL void m0_long_lock_fini(struct m0_long_lock *lock)
361 {
362  M0_ASSERT(lock->l_state == M0_LONG_LOCK_UNLOCKED);
363 
364  m0_long_lock_bob_fini(lock);
365 
366  m0_lll_tlist_fini(&lock->l_waiters);
367  m0_lll_tlist_fini(&lock->l_owners);
368 
369  m0_mutex_fini(&lock->l_lock);
370 }
371 
M0_INTERNAL void m0_long_lock_fini(struct m0_long_lock *lock)
M0_INTERNAL void m0_long_lock_link_init(struct m0_long_lock_link *link, struct m0_fom *fom, struct m0_long_lock_addb2 *addb2)
Definition: fom_long_lock.c:66
M0_INTERNAL void m0_fom_wakeup(struct m0_fom *fom)
Definition: fom.c:532
#define M0_PRE(cond)
static void ll_addb2_wait_finish(struct m0_long_lock_link *link)
M0_INTERNAL void m0_mutex_unlock(struct m0_mutex *mutex)
Definition: mutex.c:66
#define NULL
Definition: misc.h:38
#define ergo(a, b)
Definition: misc.h:293
static struct m0_bob_type long_lock_link_bob
Definition: fom_long_lock.c:57
M0_INTERNAL void m0_long_write_unlock(struct m0_long_lock *lock, struct m0_long_lock_link *link)
#define M0_SET0(obj)
Definition: misc.h:64
M0_INTERNAL void m0_mutex_lock(struct m0_mutex *mutex)
Definition: mutex.c:49
M0_ADDB2_ADD(M0_AVI_FS_CREATE, new_fid.f_container, new_fid.f_key, mode, rc)
const char * bt_name
Definition: bob.h:73
static bool link_invariant(const struct m0_long_lock_link *link)
M0_BOB_DEFINE(M0_INTERNAL, &long_lock_bob, m0_long_lock)
#define M0_ENTRY(...)
Definition: trace.h:170
M0_INTERNAL bool m0_long_write_lock(struct m0_long_lock *lk, struct m0_long_lock_link *link, int next_phase)
M0_INTERNAL bool m0_long_lock(struct m0_long_lock *lock, bool write, struct m0_long_lock_link *link, int next_phase)
static void ll_addb2_wait_start(struct m0_long_lock_link *link)
static const struct m0_bob_type long_lock_bob
Definition: fom_long_lock.c:49
M0_INTERNAL void m0_long_unlock(struct m0_long_lock *lock, struct m0_long_lock_link *link)
#define M0_ASSERT(cond)
M0_INTERNAL bool m0_mutex_is_locked(const struct m0_mutex *mutex)
Definition: mutex.c:95
m0_time_t m0_time_now(void)
Definition: time.c:134
M0_INTERNAL bool m0_fom_group_is_locked(const struct m0_fom *fom)
Definition: fom.c:229
M0_INTERNAL void m0_long_lock_link_fini(struct m0_long_lock_link *link)
Definition: fom_long_lock.c:76
static int next[]
Definition: cp.c:248
M0_INTERNAL void m0_mutex_init(struct m0_mutex *mutex)
Definition: mutex.c:35
#define M0_POST(cond)
M0_TL_DEFINE(m0_lll, M0_INTERNAL, struct m0_long_lock_link)
static bool lock_invariant(const struct m0_long_lock *lock)
Definition: dump.c:103
static void ll_addb2_reset(struct m0_long_lock_link *link)
Definition: fom_long_lock.c:84
static struct m0_clink l[NR]
Definition: chan.c:37
M0_INTERNAL bool m0_long_is_read_locked(struct m0_long_lock *lock, const struct m0_fom *fom)
M0_INTERNAL bool m0_long_is_write_locked(struct m0_long_lock *lock, const struct m0_fom *fom)
static bool can_lock(const struct m0_long_lock *lock, const struct m0_long_lock_link *link)
M0_INTERNAL void m0_long_lock_init(struct m0_long_lock *lock)
Definition: fom.h:481
static void ll_addb2_post(struct m0_long_lock_link *link)
Definition: fom_long_lock.c:90
M0_INTERNAL void m0_mutex_fini(struct m0_mutex *mutex)
Definition: mutex.c:42
M0_INTERNAL void m0_long_read_unlock(struct m0_long_lock *lock, struct m0_long_lock_link *link)
M0_INTERNAL bool m0_long_read_lock(struct m0_long_lock *lk, struct m0_long_lock_link *link, int next_phase)
void m0_fom_phase_set(struct m0_fom *fom, int phase)
Definition: fom.c:1688
static void grant(struct m0_long_lock *lock, struct m0_long_lock_link *link)
M0_INTERNAL void m0_fom_ll_global_init(void)
Definition: fom_long_lock.c:60
M0_TL_DESCR_DEFINE(m0_lll, "list of lock-links in longlock", M0_INTERNAL, struct m0_long_lock_link, lll_lock_linkage, lll_magix, M0_FOM_LL_LINK_MAGIC, M0_FOM_LL_LINK_MAGIC)
M0_INTERNAL void m0_bob_type_tlist_init(struct m0_bob_type *bt, const struct m0_tl_descr *td)
Definition: bob.c:41
#define offsetof(typ, memb)
Definition: misc.h:29
#define m0_tl_exists(name, var, head,...)
Definition: tlist.h:774
static void unlock(struct m0_long_lock *lock, struct m0_long_lock_link *link, bool check_ownership)
static struct m0_addb2_frame_header last
Definition: storage.c:93
static bool lock(struct m0_long_lock *lock, struct m0_long_lock_link *link, int next_phase)
#define m0_tl_forall(name, var, head,...)
Definition: tlist.h:735