Motr  M0
glob.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016-2020 Seagate Technology LLC and/or its Affiliates
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * For any questions about this software or licensing,
17  * please email opensource@seagate.com or cortx-questions@seagate.com.
18  *
19  */
20 
21 
28 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_CONF
29 #include "lib/trace.h"
30 
31 #include "conf/glob.h"
32 #include "conf/obj_ops.h" /* m0_conf_obj_ops */
33 #include "conf/dir.h" /* m0_conf_dir_tl */
34 #include "lib/errno.h" /* E2BIG */
35 #include "lib/string.h" /* m0_vsnprintf */
36 
45 };
46 
47 static int conf_glob_step(struct m0_conf_glob *glob,
48  const struct m0_conf_obj **target);
49 static int conf_glob_err(struct m0_conf_glob *glob, int errcode,
50  const struct m0_conf_obj *obj,
51  const struct m0_fid *path);
52 
53 M0_INTERNAL void m0_conf__glob_init(struct m0_conf_glob *glob,
55  const struct m0_conf_cache *cache,
56  const struct m0_conf_obj *origin,
57  const struct m0_fid *path)
58 {
59  size_t i;
60 
61  M0_PRE(cache != NULL || origin != NULL);
62  M0_PRE(ergo(origin != NULL && cache != NULL,
63  origin->co_cache == cache));
65 
66  for (i = 0; i < ARRAY_SIZE(glob->cg_path) && m0_fid_is_set(&path[i]);
67  ++i)
68  glob->cg_path[i] = path[i];
69  M0_ASSERT_INFO(IS_IN_ARRAY(i, glob->cg_path), "Path is too long,"
70  " consider increasing M0_CONF_PATH_MAX");
71  glob->cg_path[i] = M0_FID0; /* terminate the path */
72 
73  glob->cg_cache = cache ?: origin->co_cache;
74  glob->cg_origin = origin ?: m0_conf_cache_lookup(cache,
76  M0_ASSERT_INFO(glob->cg_origin != NULL, "No root object");
78  "Conf object is not ready: "FID_F,
79  FID_P(&glob->cg_origin->co_id));
80 
81  glob->cg_flags = flags;
82  glob->cg_errfunc = errfunc;
83  glob->cg_depth = 0;
84  glob->cg_down_p = true;
85  M0_SET_ARR0(glob->cg_trace);
86  glob->cg_trace[0] = glob->cg_origin;
87 #ifdef DEBUG
88  glob->cg_debug_print = false;
89 #endif
90 }
91 
92 M0_INTERNAL int m0_conf_glob(struct m0_conf_glob *glob, uint32_t nr,
93  const struct m0_conf_obj **objv)
94 {
95  uint32_t filled = 0;
96  int rc;
97 
98  M0_ENTRY();
100  while (filled < nr) {
101  rc = conf_glob_step(glob, &objv[filled]);
102  if (rc < 0)
103  return M0_ERR(rc);
104  if (rc == CONF_GLOB_END)
105  return M0_RC(filled);
106  if (rc == CONF_GLOB_TARGET)
107  ++filled;
108  else
110  }
111  return M0_RC(filled);
112 }
113 
114 M0_INTERNAL char *
115 m0_conf_glob_error(const struct m0_conf_glob *glob, char *buf, size_t buflen)
116 {
117  M0_PRE(_0C(glob->cg_errcode != 0) && _0C(glob->cg_errobj != NULL) &&
118  _0C(glob->cg_errpath != NULL));
119  M0_PRE(buf != NULL && buflen > 0);
120 
121  if (glob->cg_errcode == -EPERM) {
123  return m0_vsnprintf(buf, buflen, "Conf object is not ready: "
124  FID_F, FID_P(&glob->cg_errobj->co_id));
125  }
126  M0_ASSERT(glob->cg_errcode == -ENOENT);
127  return m0_vsnprintf(buf, buflen, "Unreachable path: "FID_F"/"FID_F,
128  FID_P(&glob->cg_errobj->co_id),
129  FID_P(glob->cg_errpath));
130 }
131 
132 static void conf_glob_turn(struct m0_conf_glob *glob)
133 {
134  glob->cg_down_p = !glob->cg_down_p;
135 }
136 
137 static int
138 conf_glob_down(struct m0_conf_glob *glob, const struct m0_conf_obj **target)
139 {
140  uint32_t *depth = &glob->cg_depth;
141  const struct m0_fid *elem = &glob->cg_path[*depth];
142  const struct m0_conf_obj *obj = glob->cg_trace[*depth];
143  struct m0_conf_obj *x;
144  int rc;
145 
146  M0_ENTRY("depth=%"PRIu32" obj="FID_F" elem="FID_F,
147  *depth, FID_P(&obj->co_id), FID_P(elem));
148  M0_PRE(glob->cg_down_p);
149  M0_PRE(obj->co_status == M0_CS_READY);
150 
151  if (!m0_fid_is_set(elem)) { /* end of path? */
152  /* target object reached */
153  conf_glob_turn(glob);
154  *target = obj;
155  return M0_RC(CONF_GLOB_TARGET);
156  }
157  M0_CNT_INC(*depth);
159  M0_ASSERT(glob->cg_trace[*depth] == NULL);
160 
161  if (m0_fid_eq(elem, &M0_CONF_ANY_FID)) {
162  const struct m0_conf_dir *dir = M0_CONF_CAST(obj, m0_conf_dir);
163  if (m0_conf_dir_tlist_is_empty(&dir->cd_items)) {
164  /* empty directory ==> detour */
165  conf_glob_turn(glob);
166  M0_CNT_DEC(*depth);
167  return M0_RC(CONF_GLOB_CONT);
168  }
169  obj = glob->cg_trace[*depth] =
170  m0_conf_dir_tlist_head(&dir->cd_items);
171  if (obj->co_status == M0_CS_READY)
172  return M0_RC(CONF_GLOB_CONT); /* continue descent */
173  /* stub ==> stop or detour */
174  conf_glob_turn(glob);
175  return M0_RC(conf_glob_err(glob, -EPERM, obj, elem));
176  } else {
177  rc = obj->co_ops->coo_lookup(obj, elem, &x);
178  if (rc != 0)
179  M0_ASSERT(rc == -ENOENT); /* no such object */
180  else if (x->co_status != M0_CS_READY)
181  rc = -EPERM; /* stub */
182 
183  if (rc == 0) {
184  glob->cg_trace[*depth] = x;
185  return M0_RC(CONF_GLOB_CONT); /* continue descent */
186  }
187  /* stop or detour */
188  conf_glob_turn(glob);
189  M0_CNT_DEC(*depth);
190  return M0_RC(conf_glob_err(glob, rc, rc == -ENOENT ? obj : x,
191  elem));
192  }
193 }
194 
195 static int conf_glob_up(struct m0_conf_glob *glob)
196 {
197  uint32_t *depth = &glob->cg_depth;
198  const struct m0_fid *elem;
199  const struct m0_conf_dir *dir;
200  const struct m0_conf_obj *obj;
201 
202  M0_ENTRY("depth=%"PRIu32, *depth);
203  M0_PRE(!glob->cg_down_p);
204 
205  if (*depth == 0)
206  return M0_RC(CONF_GLOB_END); /* end of traversal */
207 
208  elem = &glob->cg_path[*depth - 1];
209  if (elem->f_container != M0_CONF_ANY_FID.f_container)
210  /*
211  * All fids in M0_CONF_REL_FIDS have the same .f_container
212  * part (0x2f00000000000000); see the use of
213  * M0_CONF_REL_FIDS in conf/objs/common.c.
214  *
215  * `elem' is not in M0_CONF_REL_FIDS ==>
216  * `elem' is a fid of a conf object.
217  *
218  * Since conf cache cannot have two conf
219  * objects with the same fid, it would be
220  * pointless for conf_glob_up() to raise
221  * above this object --- no other path
222  * withinin the conf graph would lead
223  * to `elem' conf object.
224  */
225  return M0_RC(CONF_GLOB_END); /* end of traversal */
226  if (!m0_fid_eq(elem, &M0_CONF_ANY_FID)) {
227  glob->cg_trace[*depth] = NULL;
228  M0_CNT_DEC(*depth);
229  return M0_RC(CONF_GLOB_CONT); /* continue ascent */
230  }
231  dir = M0_CONF_CAST(glob->cg_trace[*depth - 1], m0_conf_dir);
232  obj = glob->cg_trace[*depth] =
233  m0_conf_dir_tlist_next(&dir->cd_items, glob->cg_trace[*depth]);
234  if (obj == NULL) {
235  /* no more items in this dir */
236  M0_CNT_DEC(*depth);
237  return M0_RC(CONF_GLOB_CONT); /* continue ascent */
238  }
239  /* found a sibling */
240  if (obj->co_status == M0_CS_READY) {
241  conf_glob_turn(glob);
242  return M0_RC(CONF_GLOB_CONT); /* descend */
243  }
244  /* stub ==> stop or try again (with another sibling) */
245  return M0_RC(conf_glob_err(glob, -EPERM, obj, elem));
246 }
247 
248 #ifdef DEBUG
249 static void conf_glob_step_pre(const struct m0_conf_glob *glob)
250 {
251  if (glob->cg_debug_print) {
252  char marker;
253  uint32_t i;
254 
255  for (i = 0; m0_fid_is_set(&glob->cg_path[i]); ++i) {
256  marker = i == glob->cg_depth ?
257  "^v"[!!glob->cg_down_p] : ' ';
258  if (glob->cg_trace[i] == NULL)
259  M0_LOG(M0_DEBUG, "%c%u "FID_F" NULL", marker,
260  i, FID_P(&glob->cg_path[i]));
261  else
262  M0_LOG(M0_DEBUG, "%c%u "FID_F" "FID_F, marker,
263  i, FID_P(&glob->cg_path[i]),
264  FID_P(&glob->cg_trace[i]->co_id));
265  }
266  }
267 }
268 
269 static void conf_glob_step_post(const struct m0_conf_glob *glob, int retval,
270  const struct m0_conf_obj *obj)
271 {
272  if (glob->cg_debug_print) {
273  if (retval == CONF_GLOB_TARGET)
274  M0_LOG(M0_DEBUG, "==> %c%u "FID_F,
275  "^v"[!!glob->cg_down_p], glob->cg_depth,
276  FID_P(&obj->co_id));
277  else
278  M0_LOG(M0_DEBUG, "==> %c%u",
279  "^v"[!!glob->cg_down_p], glob->cg_depth);
280  }
281 }
282 #else
283 # define conf_glob_step_pre(...)
284 # define conf_glob_step_post(...)
285 #endif
286 
287 static int
288 conf_glob_step(struct m0_conf_glob *glob, const struct m0_conf_obj **target)
289 {
290  int rc;
291 
292  conf_glob_step_pre(glob);
293  rc = glob->cg_down_p ? conf_glob_down(glob, target) :
294  conf_glob_up(glob);
295  conf_glob_step_post(glob, rc, *target);
296  return rc;
297 }
298 
299 static int conf_glob_err(struct m0_conf_glob *glob, int errcode,
300  const struct m0_conf_obj *obj,
301  const struct m0_fid *path)
302 {
303  int rc;
304 
305  M0_PRE(errcode < 0);
306 
307  /* Store error context for m0_conf_glob_error() to use. */
308  glob->cg_errcode = errcode;
309  glob->cg_errobj = obj;
310  glob->cg_errpath = path;
311 
312  rc = glob->cg_errfunc == NULL ? 0 :
313  glob->cg_errfunc(errcode, obj, path);
314  return (rc == 0 && glob->cg_flags & M0_CONF_GLOB_ERR) ? errcode : rc;
315 }
316 
317 #undef M0_TRACE_SUBSYSTEM
318 
struct m0_fid co_id
Definition: obj.h:208
Definition: beck.c:235
static size_t nr
Definition: dump.c:1505
#define M0_PRE(cond)
const struct m0_conf_obj * cg_trace[M0_CONF_PATH_MAX+1]
Definition: glob.h:119
int const char const void size_t int flags
Definition: dir.c:328
#define NULL
Definition: misc.h:38
const struct m0_conf_obj * cg_origin
Definition: glob.h:108
#define ergo(a, b)
Definition: misc.h:293
static bool x
Definition: sm.c:168
int cg_flags
Definition: glob.h:83
M0_INTERNAL struct m0_conf_obj * m0_conf_cache_lookup(const struct m0_conf_cache *cache, const struct m0_fid *id)
Definition: cache.c:106
#define M0_LOG(level,...)
Definition: trace.h:167
const struct m0_conf_cache * cg_cache
Definition: glob.h:105
m0_conf_glob_errfunc_t cg_errfunc
Definition: glob.h:98
M0_INTERNAL void m0_conf__glob_init(struct m0_conf_glob *glob, int flags, m0_conf_glob_errfunc_t errfunc, const struct m0_conf_cache *cache, const struct m0_conf_obj *origin, const struct m0_fid *path)
Definition: glob.c:53
uint32_t cg_depth
Definition: glob.h:122
struct m0_conf_cache * co_cache
Definition: obj.h:251
M0_INTERNAL bool m0_fid_is_set(const struct m0_fid *fid)
Definition: fid.c:106
static struct foo * obj
Definition: tlist.c:302
Definition: sock.c:887
static int conf_glob_step(struct m0_conf_glob *glob, const struct m0_conf_obj **target)
Definition: glob.c:288
return M0_RC(rc)
#define M0_ENTRY(...)
Definition: trace.h:170
int(* m0_conf_glob_errfunc_t)(int errcode, const struct m0_conf_obj *obj, const struct m0_fid *path)
Definition: glob.h:72
int i
Definition: dir.c:1033
static unsigned depth
Definition: base.c:377
#define conf_glob_step_post(...)
Definition: glob.c:284
#define M0_SET_ARR0(arr)
Definition: misc.h:72
return M0_ERR(-EOPNOTSUPP)
#define conf_glob_step_pre(...)
Definition: glob.c:283
M0_INTERNAL char * m0_conf_glob_error(const struct m0_conf_glob *glob, char *buf, size_t buflen)
Definition: glob.c:115
#define M0_ASSERT(cond)
static int errfunc(int errcode, const struct m0_conf_obj *obj, const struct m0_fid *path)
Definition: glob.c:200
M0_INTERNAL bool m0_conf_cache_is_locked(const struct m0_conf_cache *cache)
Definition: cache.c:60
uint64_t f_container
Definition: fid.h:39
static void conf_glob_turn(struct m0_conf_glob *glob)
Definition: glob.c:132
#define M0_CONF_CAST(ptr, type)
Definition: obj.h:780
#define FID_P(f)
Definition: fid.h:77
M0_INTERNAL bool m0_fid_eq(const struct m0_fid *fid0, const struct m0_fid *fid1)
Definition: fid.c:164
const struct m0_conf_obj * cg_errobj
Definition: glob.h:101
#define PRIu32
Definition: types.h:66
#define M0_CNT_INC(cnt)
Definition: arith.h:226
Definition: fid.h:38
static int conf_glob_err(struct m0_conf_glob *glob, int errcode, const struct m0_conf_obj *obj, const struct m0_fid *path)
Definition: glob.c:299
const struct m0_fid M0_CONF_ROOT_FID
Definition: root.c:226
#define _0C(exp)
Definition: assert.h:311
#define IS_IN_ARRAY(idx, array)
Definition: misc.h:311
enum m0_conf_status co_status
Definition: obj.h:210
#define M0_CNT_DEC(cnt)
Definition: arith.h:219
M0_INTERNAL int m0_conf_glob(struct m0_conf_glob *glob, uint32_t nr, const struct m0_conf_obj **objv)
Definition: glob.c:92
#define M0_ASSERT_INFO(cond, fmt,...)
struct inode * dir
Definition: dir.c:1028
#define M0_FID0
Definition: fid.h:93
static int conf_glob_down(struct m0_conf_glob *glob, const struct m0_conf_obj **target)
Definition: glob.c:138
int cg_errcode
Definition: glob.h:100
conf_glob_res
Definition: glob.c:38
struct m0_fid cg_path[M0_CONF_PATH_MAX+1]
Definition: glob.h:116
int32_t rc
Definition: trigger_fop.h:47
#define ARRAY_SIZE(a)
Definition: misc.h:45
const struct m0_fid * cg_errpath
Definition: glob.h:102
static int conf_glob_up(struct m0_conf_glob *glob)
Definition: glob.c:195
bool cg_down_p
Definition: glob.h:125
#define FID_F
Definition: fid.h:75
M0_INTERNAL char * m0_vsnprintf(char *buf, size_t buflen, const char *format,...)
Definition: string.c:84