Motr  M0
oid.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 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 
33 #include "motr/client.h"
34 #include "motr/st/st_misc.h"
35 
36 #ifdef __KERNEL__
37 
38 #include <linux/module.h>
39 
40 #else
41 
42 #include <stdlib.h>
43 #include <stdint.h>
44 #include <sys/time.h>
45 #include <sys/types.h>
46 #include <errno.h>
47 #include <pthread.h> /* for pthread_mutex_xxx */
48 
49 static pthread_mutex_t oid_extent_list_lock;
50 
51 #endif
52 
53 struct oid_extent {
54  uint64_t oe_start;
55  uint64_t oe_range;
58 };
59 
60 /*
61  * List head of extents. It contains all free object IDs when
62  * the st framework is up and will split/merge into multiple
63  * extents when the ST is running.
64  */
65 static struct oid_extent oid_extent_lh = {
66  .oe_start = 0x100000UL,
67  .oe_range = 0xfffffffffffffeffUL,
68  .oe_prev = &oid_extent_lh,
70 };
71 
72 enum {
73  M0_MIN_APP_OID = 0x100000UL
74 };
75 
76 static void oid_extent_lock(void)
77 {
78 #ifndef __KERNEL__
79  pthread_mutex_lock(&oid_extent_list_lock);
80 #endif
81 }
82 
83 static void oid_extent_unlock(void)
84 {
85 #ifndef __KERNEL__
86  pthread_mutex_unlock(&oid_extent_list_lock);
87 #endif
88 }
89 
90 static int oid_extent_is_overlapped(uint64_t start1, uint64_t range1,
91  uint64_t start2, uint64_t range2)
92 {
93 
94  if (start1 > start2 && start1 < start2 + range2)
95  return 1;
96 
97  if (start2 > start1 && start2 < start1 + range1)
98  return 1;
99 
100  return 0;
101 }
102 
103 static void oid_extent_delete(struct oid_extent *oe)
104 {
105  struct oid_extent *prev;
106  struct oid_extent *next;
107 
108  /*
109  * If someone is trying to delete list head, this means
110  * we run out of free object IDs. Treat this differently.
111  */
112  if (oe == &oid_extent_lh) {
113  oe->oe_range = 0x0UL;
114  oe->oe_next = &oid_extent_lh;
115  oe->oe_prev = &oid_extent_lh;
116  return;
117  }
118 
119  /* Be careful for the extents next to the head*/
120  prev = oe->oe_prev;
121  next = oe->oe_next;
122  prev->oe_next = next;
123  next->oe_prev = prev;
124 
125  /* remember to free memory*/
126  mem_free(oe);
127 }
128 
129 static void oid_extent_split(struct oid_extent *oe,
130  uint64_t wanted)
131 {
132  uint64_t allocated;
133 
134  allocated = (oe->oe_range < wanted)?oe->oe_range:wanted;
135 
136  oe->oe_start += allocated;
137  oe->oe_range -= allocated;
138 
139  if (oe->oe_range == 0)
140  oid_extent_delete(oe);
141 }
142 
143 static void oid_extent_merge(struct oid_extent *oe,
144  uint64_t s_oid, uint64_t nr_oids,
145  int direction)
146 {
147  struct oid_extent *prev;
148  struct oid_extent *next;
149 
150  /* Merge with extent in front of me*/
151  if (direction == 0) {
152  oe->oe_range += nr_oids;
153 
154  next = oe->oe_next;
155  if (next != &oid_extent_lh
156  && (next->oe_start == oe->oe_start + oe->oe_range))
157  {
158  oe->oe_range += next->oe_range;
160  }
161 
162  return;
163  }
164 
165  /* Merge with extent behind me*/
166  oe->oe_start = s_oid;
167  oe->oe_range += nr_oids;
168 
169  prev = oe->oe_prev;
170  if (prev != &oid_extent_lh
171  && (s_oid == prev->oe_start + prev->oe_range))
172  {
173  prev->oe_range += oe->oe_range;
174  oid_extent_delete(oe);
175  }
176 
177  return;
178 }
179 
183 static void oid_extent_insert_head(uint64_t s_oid, uint64_t nr_oids)
184 {
185  uint64_t a;
186  struct oid_extent *lhp;
187  struct oid_extent *new_oe;
188 
189  lhp = &oid_extent_lh;
190 
191  /* if all object IDs have been allocated */
192  if (lhp->oe_range == 0) {
193  lhp->oe_start = s_oid;
194  lhp->oe_range = nr_oids;
195  return;
196  }
197 
198  /* can we merge? */
199  if (lhp->oe_start == s_oid + nr_oids
200  || (lhp->oe_start + lhp->oe_range) == s_oid)
201  {
202  lhp->oe_start =
203  (lhp->oe_start < s_oid)?lhp->oe_start:s_oid;
204  lhp->oe_range = lhp->oe_range + nr_oids;
205 
206  return;
207  }
208 
209  /* Overlapping is not allowed */
211  lhp->oe_start, lhp->oe_range, s_oid, nr_oids))
212  return;
213 
214  /* Allocate memory and initialise extent */
215  new_oe = mem_alloc(sizeof *new_oe);
216  if (new_oe == NULL)
217  return;
218 
219  new_oe->oe_start = s_oid;
220  new_oe->oe_range = nr_oids;
221 
222  /* Ensure that extent list is in increasing order */
223  if (lhp->oe_start > new_oe->oe_start) {
224  a = lhp->oe_start;
225  lhp->oe_start = new_oe->oe_start;
226  new_oe->oe_start = a;
227 
228  a = lhp->oe_range;
229  lhp->oe_range = new_oe->oe_range;
230  new_oe->oe_range =a;
231  }
232 
233  new_oe->oe_prev = lhp;
234  new_oe->oe_next = lhp;
235  lhp->oe_prev = new_oe;
236  lhp->oe_next = new_oe;
237 }
238 
245 static void oid_extent_insert(uint64_t s_oid, uint64_t nr_oids)
246 {
247  struct oid_extent *lhp;
248  struct oid_extent *prev;
249  struct oid_extent *oe;
250  struct oid_extent *new_oe;
251 
252  oid_extent_lock();
253  lhp = &oid_extent_lh;
254 
255  /*
256  * In some cases released oids are to insert in head.
257  * A. Only one extent (head).
258  * B. s_oid is smaller than the current oid in head.
259  */
260  if ((lhp->oe_prev == lhp && lhp->oe_next == lhp)
261  || s_oid < lhp->oe_start)
262  {
263  oid_extent_insert_head(s_oid, nr_oids);
264  goto UNLOCK_EXIT;
265  }
266 
267  /* Search for the right place*/
268  prev = lhp;
269  oe = lhp->oe_next;
270  while (oe != lhp) {
271  if (s_oid >= prev->oe_start + prev->oe_range
272  && oe->oe_start >= s_oid + nr_oids)
273  break;
274 
275  prev = oe;
276  oe = oe->oe_next;
277  }
278 
279  /* Can we merge? It is possible to merge 3 extents*/
280  if (s_oid == prev->oe_start + prev->oe_range) {
281  oid_extent_merge(prev, s_oid, nr_oids, 0);
282  goto UNLOCK_EXIT;
283  } else if (oe->oe_start == s_oid + nr_oids) {
284  oid_extent_merge(oe, s_oid, nr_oids, 1);
285  goto UNLOCK_EXIT;
286  }
287 
288  /* Allocate a new extent */
289  new_oe = (struct oid_extent *)
290  mem_alloc(sizeof *new_oe);
291  if (new_oe == NULL)
292  goto UNLOCK_EXIT;
293 
294  new_oe->oe_start = s_oid;
295  new_oe->oe_range = nr_oids;
296  new_oe->oe_prev = prev;
297  new_oe->oe_next = oe;
298  oe->oe_prev = new_oe;
299  prev->oe_next = new_oe;
300 
301 UNLOCK_EXIT:
303 }
304 
305 static void oid_fill(struct m0_uint128 *oids, uint64_t s_id, int nr_id)
306 {
307  int i;
308 
309  for (i = 0; i < nr_id; i++) {
310  oids[i].u_hi = 0x0UL;
311  oids[i].u_lo = M0_MIN_APP_OID + s_id + i;
312  }
313 }
314 
322 static uint64_t oid_alloc(struct m0_uint128 *oids, uint64_t nr_oids)
323 {
324  uint64_t nr_allocated;
325  uint64_t nr_wanted;
326  struct oid_extent *oe;
327  struct oid_extent *next;
328  struct oid_extent *lhp;
329 
330  /* lock the extent list first */
331  oid_extent_lock();
332  lhp = &oid_extent_lh;
333 
334  /* scan the whole list*/
335  nr_allocated = 0;
336  nr_wanted = nr_oids;
337  oe = lhp;
338 
339  do {
340  next = oe->oe_next;
341 
342  /* This exent has enough free IDs*/
343  if (oe->oe_range > nr_wanted) {
344  oid_fill(oids + nr_allocated, oe->oe_start, nr_wanted);
345  oid_extent_split(oe, nr_wanted);
346  nr_allocated += nr_wanted;
347  nr_wanted -= 0;
348 
349  break;
350  }
351 
352  /* This extent has less free IDs than required */
353  oid_fill(oids + nr_allocated, oe->oe_start, oe->oe_range);
354  nr_allocated += oe->oe_range;
355  nr_wanted -= oe->oe_range;
356  oid_extent_delete(oe);
357 
358  oe = next;
359  } while (oe != lhp && nr_wanted != 0);
360 
361  /* unlock */
363 
364  return nr_allocated;
365 }
366 
373 int oid_get(struct m0_uint128 *oid)
374 {
375  uint64_t nr_allocated;
376 
377  nr_allocated = oid_alloc(oid, 1);
378  if (nr_allocated == 0)
379  return -EAGAIN;
380 
381  return 0;
382 }
383 
384 void oid_put(struct m0_uint128 oid)
385 {
386  oid_extent_insert(oid.u_lo, 1);
387 }
388 
397 uint64_t oid_get_many(struct m0_uint128 *oids, uint64_t nr_oids)
398 {
399  uint64_t nr_allocated;
400 
401  nr_allocated = oid_alloc(oids, nr_oids);
402  if (nr_allocated == 0)
403  return 0;
404 
405  return nr_allocated;
406 }
407 
408 void oid_put_many(struct m0_uint128 *oids, uint64_t nr_oids)
409 {
410  uint64_t i;
411  uint64_t j;
412 
413  for (i = 0; i < nr_oids; ) {
414  /* look for those oids are next to each other */
415  for (j = i + 1; j < nr_oids; j++) {
416  if (oids[j].u_hi != oids[j-1].u_hi
417  || oids[j].u_lo != oids[j-1].u_lo + 1)
418  break;
419  }
420 
421  oid_extent_insert(oids[i].u_lo, j - i);
422  i = j;
423  }
424 }
425 
427 {
428  uint64_t offset;
429 
430  /*
431  * Set the values of extent list head: the oe_start is
432  * offseted with a random number in order to enable multiple runs
433  * of ST (this is different from setting the number of rounds in
434  * one single ST run although they can achieve the same thing).
435  *
436  * We use the value of tv_usec in struct timeval returned by
437  * time_now(). [generate_random() isn't used as random() creates
438  * pseudo random number]
439  */
440  offset = time_now() % 0xffffUL;
441 
442  oid_extent_lh.oe_start = M0_MIN_APP_OID + offset; //0xffffUL * offset;
443  oid_extent_lh.oe_range = 0xffffffffffffffffUL - oid_extent_lh.oe_start;
446 
447 #ifdef __KERNEL__
448  return 0;
449 #else
450  return pthread_mutex_init(&oid_extent_list_lock, NULL);
451 #endif
452 }
453 
455 {
456 #ifdef __KERNEL__
457  return 0;
458 #else
459  return pthread_mutex_destroy(&oid_extent_list_lock);
460 #endif
461 }
462 
463 /*
464  * Local variables:
465  * c-indentation-style: "K&R"
466  * c-basic-offset: 8
467  * tab-width: 8
468  * fill-column: 80
469  * scroll-step: 1
470  * End:
471  */
static void oid_extent_lock(void)
Definition: oid.c:76
static uint64_t oid_alloc(struct m0_uint128 *oids, uint64_t nr_oids)
Definition: oid.c:322
static pthread_mutex_t oid_extent_list_lock
Definition: oid.c:49
#define NULL
Definition: misc.h:38
uint64_t u_lo
Definition: types.h:58
uint64_t oid_get_many(struct m0_uint128 *oids, uint64_t nr_oids)
Definition: oid.c:397
static struct m0_atomic64 allocated
Definition: memory.c:101
int oid_allocator_fini(void)
Definition: oid.c:454
static struct oid_extent oid_extent_lh
Definition: oid.c:65
Definition: oid.c:53
int i
Definition: dir.c:1033
static int oid_extent_is_overlapped(uint64_t start1, uint64_t range1, uint64_t start2, uint64_t range2)
Definition: oid.c:90
if(value==NULL)
Definition: dir.c:350
static void oid_extent_insert_head(uint64_t s_oid, uint64_t nr_oids)
Definition: oid.c:183
int oid_get(struct m0_uint128 *oid)
Definition: oid.c:373
static void oid_extent_delete(struct oid_extent *oe)
Definition: oid.c:103
struct oid_extent * oe_next
Definition: oid.c:57
static int next[]
Definition: cp.c:248
uint64_t u_hi
Definition: types.h:57
uint64_t u_hi
Definition: types.h:36
static m0_bindex_t offset
Definition: dump.c:173
static void mem_free(const struct m0_be_btree *btree, struct m0_be_tx *tx, void *ptr)
Definition: btree.c:102
void oid_put_many(struct m0_uint128 *oids, uint64_t nr_oids)
Definition: oid.c:408
struct oid_extent * oe_prev
Definition: oid.c:56
uint64_t time_now(void)
Definition: st_misc.c:69
static void oid_extent_merge(struct oid_extent *oe, uint64_t s_oid, uint64_t nr_oids, int direction)
Definition: oid.c:143
static void * mem_alloc(const struct m0_be_btree *btree, struct m0_be_tx *tx, m0_bcount_t size, uint64_t zonemask)
Definition: btree.c:116
static void oid_fill(struct m0_uint128 *oids, uint64_t s_id, int nr_id)
Definition: oid.c:305
int oid_allocator_init(void)
Definition: oid.c:426
uint64_t oe_range
Definition: oid.c:55
static void oid_extent_split(struct oid_extent *oe, uint64_t wanted)
Definition: oid.c:129
void oid_put(struct m0_uint128 oid)
Definition: oid.c:384
uint64_t u_lo
Definition: types.h:37
static void oid_extent_insert(uint64_t s_oid, uint64_t nr_oids)
Definition: oid.c:245
static void oid_extent_unlock(void)
Definition: oid.c:83
uint64_t oe_start
Definition: oid.c:54