Motr  M0
ufid.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 
23 #include "helpers/ufid.h"
24 
25 #include "lib/errno.h"
26 #include "lib/arith.h"
27 #include "lib/finject.h"
28 
29 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_CLIENT
30 #include "lib/trace.h"
31 
32 static bool ufid_invariant(struct m0_ufid *ufid)
33 {
34  return M0_RC(!(ufid->uf_salt & ~M0_UFID_SALT_MASK ||
35  ufid->uf_seq_id & ~M0_UFID_SEQID_MASK ||
36  ufid->uf_gen_id & ~M0_UFID_GENID_MASK ||
38 }
39 
45 static void ufid_salt_refresh(struct m0_ufid_generator *gr)
46 {
47  m0_time_t now;
48 
49  now = m0_time_now();
51 }
52 
59 static int
61 {
62  uint32_t new_gen_id = 0;
63  uint32_t ts;
64  int retry_count = M0_UFID_RETRY_MAX + 1;
65 
66  M0_ENTRY();
67 
68  if (M0_FI_ENABLED("retries_exhausted"))
69  retry_count = 1;
70 
71  while (--retry_count) {
72  /* Note: m0_time_now returns value in nanoseconds. */
74  if (M0_FI_ENABLED("clock_lt_base_ts"))
75  ts = M0_UFID_BASE_TS - 1;
76 
77  /* Time must be larger than base time set. */
78  if (ts <= M0_UFID_BASE_TS)
79  return M0_ERR(-ETIME);
80 
81  /* Calculate the new generation id. */
82  new_gen_id = ts - M0_UFID_BASE_TS;
83  if (M0_FI_ENABLED("clock_skew"))
84  new_gen_id = 0;
85 
86  /*
87  * Make sure the generation has changed reasonably since
88  * the last time.
89  */
90  if (gr->ufg_ufid_cur.uf_gen_id >
91  new_gen_id + M0_UFID_CLOCK_SKEW_LIMIT) {
93  "Large clock skew Detected: old=0x%X new=0x%X.",
94  gr->ufg_ufid_cur.uf_gen_id, new_gen_id);
95 
96  return M0_ERR(-ETIME);
97  }
98 
99  if (new_gen_id <= gr->ufg_ufid_cur.uf_gen_id) {
100  M0_LOG(M0_WARN,
101  "Clock reset/skew detected: old=0x%X new=0x%X."
102  " Retrying...",
103  gr->ufg_ufid_cur.uf_gen_id, new_gen_id);
104  m0_nanosleep(m0_time(1, 0), NULL);
105  continue;
106  }
107 
108  gr->ufg_ufid_cur.uf_gen_id = new_gen_id;
109  break;
110  }
111 
112  if (retry_count == 0) /* We have exhausted all the retries, fail */
113  return M0_ERR(-ETIME);
114  else
115  return M0_RC(0);
116 }
117 
125 {
126  uint64_t proc_id_64;
127  struct m0_fid proc_fid;
128  struct m0_client *m0c;
129 
130  M0_ENTRY();
131  M0_PRE(gr != NULL);
132 
133  m0c = gr->ufg_m0c;
134  M0_ASSERT(m0c != NULL);
136  proc_id_64 = proc_fid.f_key;
137 
138  if (M0_FI_ENABLED("proc_id_overflow"))
139  proc_id_64 = M0_UFID_PROCID_MAX + 1;
140  if (M0_FI_ENABLED("proc_id_warn"))
141  proc_id_64 = (M0_UFID_PROCID_MAX >>
143 
144  if (proc_id_64 >> M0_UFID_PROCID_BITS > 0) {
145  /*
146  * Exceeded allotted bits. service_id will no longer be unique.
147  * FID generator can no longer be used.
148  */
149  M0_LOG(M0_ERROR, "Process ID overflowed.");
150  return M0_ERR(-EOVERFLOW);
151  }
152 
153  if (proc_id_64 >> M0_UFID_PROCID_SAFE_BITS > 0)
154  /*
155  * The last bits of our allotted bits are being used.
156  * Raise warning message to allow developers to deal with
157  * potential process id overflow.
158  */
159  M0_LOG(M0_WARN, "Process ID exceeded safety threshold !");
160 
162  (uint32_t)(proc_id_64 & M0_UFID_PROCID_MASK);
163 
164  return M0_RC(0);
165 }
166 
179  uint32_t nr_seqs)
180 {
181  int rc = 0;
182  struct m0_ufid *cursor;
183 
184  M0_ENTRY();
185  M0_PRE(gr != NULL);
186  M0_PRE(nr_seqs <= M0_UFID_SEQID_MAX);
187 
188  /*
189  * If seqence id is about to exhaust then generate new
190  * generation ID. Note: the ufid generator's lock must have
191  * already be held when reaching here.
192  */
193  cursor = &gr->ufg_ufid_cur;
194  if (cursor->uf_seq_id + nr_seqs >= M0_UFID_SEQID_MAX) {
196  if (rc < 0) {
198  "Failed to refresh generation ID, rc=%d", rc);
199  return M0_ERR(rc);
200  }
201 
202  cursor->uf_seq_id = 0;
203  }
204 
205  cursor->uf_seq_id += nr_seqs;
206  return M0_RC(0);
207 }
208 
209 static void ufid_to_id128(struct m0_ufid *ufid,
210  struct m0_uint128 *id128)
211 {
212  uint64_t id_lo;
213  uint64_t id_hi;
214  uint64_t id_hi_reserved;
215  uint64_t genid_hi;
216  uint64_t genid_lo;
217  uint64_t salt;
218  uint64_t proc_id;
219  uint64_t seq_id;
220 
221  M0_ENTRY();
222  M0_PRE(ufid != NULL);
223  M0_PRE(id128 != NULL);
224  M0_PRE(ufid_invariant(ufid));
225 
226  salt = ufid->uf_salt;
227  proc_id = ufid->uf_proc_id;
228  seq_id = ufid->uf_seq_id;
229  genid_hi = ufid->uf_gen_id >> M0_UFID_GENID_LO_BITS;
230  genid_lo = ufid->uf_gen_id & M0_UFID_GENID_LO_MASK;
231 
232  id_hi_reserved = id128->u_hi & M0_UFID_HI_RESERVED;
233  id_hi = salt & M0_UFID_SALT_MASK;
234  id_hi = (id_hi << M0_UFID_GENID_HI_BITS) |
235  (genid_hi & M0_UFID_GENID_HI_MASK);
236  id_hi |= id_hi_reserved;
237 
238  id_lo = genid_lo & M0_UFID_GENID_LO_MASK;
239  id_lo = (id_lo << M0_UFID_PROCID_BITS) |
240  (proc_id & M0_UFID_PROCID_MASK);
241  id_lo = (id_lo << M0_UFID_SEQID_BITS) |
242  (seq_id & M0_UFID_SEQID_MASK);
243 
244  id128->u_hi = id_hi;
245  id128->u_lo = id_lo;
246 }
247 
249  struct m0_ufid_generator *gr)
250 {
251  int rc;
252 
253  M0_ENTRY();
254  M0_PRE(m0c != NULL && gr != NULL);
255 
256  if (gr->ufg_is_initialised)
257  return M0_RC(0);
258  gr->ufg_m0c = m0c;
259  ufid_salt_refresh(gr);
260 
261  rc = ufid_proc_id_refresh(gr);
262  if (rc < 0) {
263  M0_LOG(M0_ERROR, "%d: Can not generate service id", rc);
264  goto error;
265  }
266 
268  if (rc < 0) {
269  M0_LOG(M0_ERROR, "%d: Can not generate generation id", rc);
270  goto error;
271  }
272 
273  m0_mutex_init(&gr->ufg_lock);
274  gr->ufg_is_initialised = true;
275  return M0_RC(0);
276 
277 error:
278  M0_SET0(gr);
279  return M0_ERR(rc);
280 }
281 M0_EXPORTED(m0_ufid_init);
282 
284 {
285  M0_ENTRY();
286  M0_PRE(gr != NULL);
287 
288  if (!gr->ufg_is_initialised)
289  return;
290 
291  m0_mutex_fini(&gr->ufg_lock);
292  M0_SET0(gr);
293 
294  M0_LEAVE();
295 }
296 M0_EXPORTED(m0_ufid_fini);
297 
299  uint32_t nr_ids, uint32_t nr_skip_ids,
300  struct m0_uint128 *id128)
301 {
302  int rc = 0;
303  struct m0_ufid ufid;
304 
305  M0_ENTRY();
306  M0_PRE(id128 != NULL);
307  M0_PRE(gr != NULL);
309 
310  /*
311  * nr_skip_ids is not allowed to be larger than
312  * M0_UFID_SEQID_MAX as generation ids may not be continous.
313  */
314  if (nr_ids == 0 || nr_ids > M0_UFID_SEQID_MAX ||
315  nr_skip_ids > M0_UFID_SEQID_MAX)
316  return M0_ERR(-EINVAL);
317 
318  m0_mutex_lock(&gr->ufg_lock);
319 
320  rc = ufid_seq_id_refresh(gr, nr_skip_ids)?:
321  ufid_seq_id_refresh(gr, nr_ids);
322  if (rc < 0) {
324  return M0_ERR(rc);
325  }
326  ufid = gr->ufg_ufid_cur;
327  /* Set back to the start sequence id allocated. */
328  ufid.uf_seq_id -= nr_ids;
329 
331 
332  ufid_to_id128(&ufid, id128);
333  return M0_RC(0);
334 
335 }
336 M0_EXPORTED(m0_ufid_new);
337 
339  uint32_t nr_ids, struct m0_uint128 *id128)
340 {
341  return m0_ufid_new(gr, nr_ids, 0UL, id128);
342 };
343 M0_EXPORTED(m0_ufid_next);
344 
345 #undef M0_TRACE_SUBSYSTEM
346 
347 /*
348  * Local variables:
349  * c-indentation-style: "K&R"
350 
351  * c-basic-offset: 8
352  * tab-width: 8
353  * fill-column: 80
354  * scroll-step: 1
355  * End:
356  */
357 /*
358  * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap
359  */
#define M0_PRE(cond)
#define M0_UFID_HI_RESERVED
Definition: ufid.h:179
M0_INTERNAL void m0_mutex_unlock(struct m0_mutex *mutex)
Definition: mutex.c:66
#define NULL
Definition: misc.h:38
static void ufid_salt_refresh(struct m0_ufid_generator *gr)
Definition: ufid.c:45
uint32_t uf_seq_id
Definition: ufid.h:189
uint64_t m0_time_t
Definition: time.h:37
#define M0_LOG(level,...)
Definition: trace.h:167
M0_LEAVE()
int m0_ufid_init(struct m0_client *m0c, struct m0_ufid_generator *gr)
Definition: ufid.c:248
void m0_process_fid(const struct m0_client *m0c, struct m0_fid *proc_fid)
Definition: client_init.c:1766
#define M0_UFID_PROCID_MAX
Definition: ufid.h:182
static struct m0_clovis * m0c
Definition: main.c:25
struct m0_mutex ufg_lock
Definition: ufid.h:207
static int error
Definition: mdstore.c:64
#define M0_SET0(obj)
Definition: misc.h:64
M0_INTERNAL void m0_mutex_lock(struct m0_mutex *mutex)
Definition: mutex.c:49
m0_time_t m0_time(uint64_t secs, long ns)
Definition: time.c:41
void m0_ufid_fini(struct m0_ufid_generator *gr)
Definition: ufid.c:283
#define M0_UFID_GENID_MASK
Definition: ufid.h:171
return M0_RC(rc)
#define M0_ENTRY(...)
Definition: trace.h:170
#define M0_UFID_GENID_HI_MASK
Definition: ufid.h:172
struct m0_ufid ufg_ufid_cur
Definition: ufid.h:208
return M0_ERR(-EOPNOTSUPP)
Definition: ufid.h:184
#define M0_UFID_GENID_LO_MASK
Definition: ufid.h:173
#define M0_ASSERT(cond)
m0_time_t m0_time_now(void)
Definition: time.c:134
uint64_t u_hi
Definition: types.h:36
static char * proc_fid
Definition: m0hsm.c:45
M0_INTERNAL void m0_mutex_init(struct m0_mutex *mutex)
Definition: mutex.c:35
int m0_ufid_next(struct m0_ufid_generator *gr, uint32_t nr_ids, struct m0_uint128 *id128)
Definition: ufid.c:338
uint32_t uf_salt
Definition: ufid.h:186
#define M0_UFID_SEQID_MASK
Definition: ufid.h:175
uint64_t m0_time_seconds(const m0_time_t time)
Definition: time.c:83
#define M0_UFID_SALT_MASK
Definition: ufid.h:174
static void ufid_to_id128(struct m0_ufid *ufid, struct m0_uint128 *id128)
Definition: ufid.c:209
M0_INTERNAL uint64_t m0_rnd64(uint64_t *seed)
Definition: misc.c:100
#define M0_FI_ENABLED(tag)
Definition: finject.h:231
Definition: fid.h:38
bool ufg_is_initialised
Definition: ufid.h:202
uint32_t uf_proc_id
Definition: ufid.h:188
M0_INTERNAL void m0_mutex_fini(struct m0_mutex *mutex)
Definition: mutex.c:42
static bool ufid_invariant(struct m0_ufid *ufid)
Definition: ufid.c:32
#define M0_UFID_SEQID_MAX
Definition: ufid.h:181
struct m0_client * ufg_m0c
Definition: ufid.h:201
#define M0_UFID_PROCID_MASK
Definition: ufid.h:176
int m0_ufid_new(struct m0_ufid_generator *gr, uint32_t nr_ids, uint32_t nr_skip_ids, struct m0_uint128 *id128)
Definition: ufid.c:298
static int ufid_generation_id_refresh(struct m0_ufid_generator *gr)
Definition: ufid.c:60
uint64_t u_lo
Definition: types.h:37
static int ufid_proc_id_refresh(struct m0_ufid_generator *gr)
Definition: ufid.c:124
int32_t rc
Definition: trigger_fop.h:47
Definition: trace.h:478
uint32_t uf_gen_id
Definition: ufid.h:187
static int ufid_seq_id_refresh(struct m0_ufid_generator *gr, uint32_t nr_seqs)
Definition: ufid.c:178
int m0_nanosleep(const m0_time_t req, m0_time_t *rem)
Definition: ktime.c:73