Motr  M0
mdstore.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-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 
22 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_COB
23 #include "lib/trace.h"
24 
25 #include <sys/stat.h> /* S_ISDIR */
26 
27 #include "lib/misc.h" /* M0_SET0 */
28 #include "lib/arith.h" /* M0_3WAY, m0_align */
29 #include "lib/errno.h"
30 #include "lib/assert.h"
31 #include "lib/memory.h"
32 #include "lib/bitstring.h"
33 #include "lib/rwlock.h"
34 
35 #include "fid/fid.h"
36 #include "fop/fop.h"
37 #include "cob/cob.h"
38 #include "mdstore/mdstore.h"
39 #include "motr/magic.h"
40 
41 M0_INTERNAL int m0_mdstore_mod_init(void)
42 {
43  return 0;
44 }
45 
46 M0_INTERNAL void m0_mdstore_mod_fini(void)
47 {
48 }
49 
50 
52 #define M0_MD_FAKE_BLOCKSIZE 4096
53 #define M0_MD_FAKE_VOLUME 250000
54 
55 M0_INTERNAL int m0_mdstore_statfs(struct m0_mdstore *md,
56  struct m0_statfs *statfs)
57 {
64  M0_SET0(statfs);
65  statfs->sf_type = M0_T1FS_SUPER_MAGIC;
67  statfs->sf_blocks = M0_MD_FAKE_VOLUME;
68  statfs->sf_bfree = M0_MD_FAKE_VOLUME;
69  statfs->sf_bavail = M0_MD_FAKE_VOLUME;
70  statfs->sf_files = 1024000;
71  statfs->sf_ffree = 1024000;
73  if (md->md_root)
74  statfs->sf_root = *m0_cob_fid(md->md_root);
75  return 0;
76 }
77 
78 M0_INTERNAL int m0_mdstore_init(struct m0_mdstore *md,
79  struct m0_be_seg *db,
80  bool init_root)
81 {
82  int rc;
83 
84  M0_PRE(md != NULL && db != NULL);
85 
86  /*
87  * TODO FIXME Don't allow md_dom to be NULL here. Instead, check it
88  * by users (motr/setup, ut/ut_rpc_machine).
89  * I will reduce posibility of mistakes.
90  */
91  if (md->md_dom == NULL) {
92  /* See cs_storage_setup(). */
93  return M0_RC(-ENOENT);
94  }
95 
97  if (rc != 0)
98  return M0_RC(rc);
99 
100  if (init_root) {
101  struct m0_buf name;
102 
104  strlen(M0_COB_ROOT_NAME));
106  if (rc == 0)
107  /*
108  * Check if omgid can be allocated.
109  */
111  }
112  if (rc != 0)
114  return M0_RC(rc);
115 }
116 
117 static void mdstore_fini(struct m0_mdstore *md, bool pre_destroy)
118 {
119  if (md->md_root != NULL)
121 
122  /*
123  * During mdstore destroying we call m0_cob_domain_destroy() which
124  * includes implicit finalisation. So, avoid double finalisation.
125  */
126  if (!pre_destroy)
128 }
129 
130 M0_INTERNAL void m0_mdstore_fini(struct m0_mdstore *md)
131 {
132  mdstore_fini(md, false);
133 }
134 
135 M0_INTERNAL int m0_mdstore_create(struct m0_mdstore *md,
136  struct m0_sm_group *grp,
137  struct m0_cob_domain_id *id,
138  struct m0_be_domain *bedom,
139  struct m0_be_seg *db)
140 {
141  M0_PRE(md != NULL);
142 
143  return m0_cob_domain_create(&md->md_dom, grp, id, bedom, db);
144 }
145 
146 M0_INTERNAL int m0_mdstore_destroy(struct m0_mdstore *md,
147  struct m0_sm_group *grp,
148  struct m0_be_domain *bedom)
149 {
150  /*
151  * We have to finalise mdstore here, but can't call m0_mdstore_fini(),
152  * because m0_cob_domain_destroy() finalises cob domain inmplicitly.
153  * See m0_mdstore_fini().
154  */
155  mdstore_fini(md, true);
156 
157  return m0_cob_domain_destroy(md->md_dom, grp, bedom);
158 }
159 
160 M0_INTERNAL void
162  struct m0_be_tx_credit *accum)
163 {
165 }
166 
167 M0_INTERNAL int m0_mdstore_dir_nlink_update(struct m0_mdstore *md,
168  struct m0_fid *fid,
169  int inc,
170  struct m0_be_tx *tx)
171 {
172  struct m0_cob *cob;
173  struct m0_cob_oikey oikey;
174  int rc;
175 
176  M0_ENTRY("%+d nlinks for dir "FID_F, inc, FID_P(fid));
181  m0_cob_oikey_make(&oikey, fid, 0);
182  rc = m0_cob_locate(md->md_dom, &oikey, 0, &cob);
183  if (rc != 0) {
184  M0_LOG(M0_DEBUG, "cannot locate stat data for dir "FID_F" - %d",
185  FID_P(fid), rc);
186  goto out;
187  }
188  M0_LOG(M0_DEBUG, "%u %+d nlinks for "FID_F"<-"FID_F"/%.*s",
189  (unsigned)cob->co_nsrec.cnr_nlink, inc,
193  cob->co_nsrec.cnr_nlink += inc;
194  rc = m0_cob_update(cob, &cob->co_nsrec, NULL, NULL, tx);
195  m0_cob_put(cob);
196 out:
197  M0_LEAVE("rc: %d", rc);
198  return M0_RC(rc);
199 }
200 
201 M0_INTERNAL void
203  struct m0_be_tx_credit *accum)
204 {
207 }
208 
209 M0_INTERNAL int m0_mdstore_fcreate(struct m0_mdstore *md,
210  struct m0_fid *pfid,
211  struct m0_cob_attr *attr,
212  struct m0_cob **out,
213  struct m0_be_tx *tx)
214 {
215  struct m0_cob *cob;
216  struct m0_cob_nskey *nskey = NULL;
217  struct m0_cob_nsrec nsrec = {};
218  struct m0_cob_fabrec *fabrec = NULL;
219  struct m0_cob_omgrec omgrec = {};
220  int linklen;
221  int rc;
222 
223  M0_ENTRY();
224  M0_ASSERT(pfid != NULL);
225 
226  /* We don't allow create in .motr and .motr/fid directory. */
227  if (m0_fid_cmp(pfid, &M0_MDSERVICE_SLASH_FID) < 0) {
228  rc = -EOPNOTSUPP;
229  goto out;
230  }
231 
232  rc = m0_cob_alloc(md->md_dom, &cob);
233  if (rc != 0)
234  goto out;
235 
236  rc = m0_cob_nskey_make(&nskey, pfid, (char *)attr->ca_name.b_addr,
237  attr->ca_name.b_nob);
238  if (rc != 0) {
239  m0_cob_put(cob);
240  return M0_RC(rc);
241  }
242 
243  m0_cob_nsrec_init(&nsrec);
244  nsrec.cnr_fid = attr->ca_tfid;
245  M0_ASSERT(attr->ca_nlink > 0);
246  nsrec.cnr_nlink = attr->ca_nlink;
247  nsrec.cnr_size = attr->ca_size;
248  nsrec.cnr_blksize = attr->ca_blksize;
249  nsrec.cnr_blocks = attr->ca_blocks;
250  nsrec.cnr_atime = attr->ca_atime;
251  nsrec.cnr_mtime = attr->ca_mtime;
252  nsrec.cnr_ctime = attr->ca_ctime;
253  nsrec.cnr_lid = attr->ca_lid;
254  nsrec.cnr_pver = attr->ca_pver;
255 
256  omgrec.cor_uid = attr->ca_uid;
257  omgrec.cor_gid = attr->ca_gid;
258  omgrec.cor_mode = attr->ca_mode;
259 
260  linklen = attr->ca_link.b_addr ? attr->ca_link.b_nob : 0;
261  rc = m0_cob_fabrec_make(&fabrec, (char *)attr->ca_link.b_addr,
262  linklen);
263  if (rc != 0) {
264  m0_cob_put(cob);
265  m0_free(nskey);
266  goto out;
267  }
268 
269  rc = m0_cob_create(cob, nskey, &nsrec, fabrec, &omgrec, tx);
270  if (rc != 0) {
271  m0_cob_put(cob);
272  m0_free(nskey);
273  m0_free(fabrec);
274  } else {
275  *out = cob;
276  if (S_ISDIR(attr->ca_mode)) {
278  rc = m0_mdstore_dir_nlink_update(md, pfid, +1, tx);
279  }
280  }
281 
282 out:
283  M0_LEAVE("rc: %d", rc);
284  return M0_RC(rc);
285 }
286 
287 M0_INTERNAL void
289  struct m0_be_tx_credit *accum)
290 {
293 }
294 
295 M0_INTERNAL int m0_mdstore_link(struct m0_mdstore *md,
296  struct m0_fid *pfid,
297  struct m0_cob *cob,
298  struct m0_buf *name,
299  struct m0_be_tx *tx)
300 {
301  struct m0_cob_nskey *nskey = NULL;
302  struct m0_cob_nsrec nsrec;
303  time_t now;
304  int rc;
305 
306  M0_ENTRY();
307  M0_ASSERT(pfid != NULL);
308  M0_ASSERT(cob != NULL);
309 
310  /* We don't allow link in .motr and .motr/fid directory. */
311  if (m0_fid_cmp(pfid, &M0_MDSERVICE_SLASH_FID) < 0)
312  return M0_RC(-EOPNOTSUPP);
313 
314  time(&now);
315  M0_SET0(&nsrec);
316 
317  /*
318  * Link @nskey to a file described with @cob
319  */
320  rc = m0_cob_nskey_make(&nskey, pfid, (char *)name->b_addr,
321  name->b_nob);
322  if (rc != 0)
323  return M0_RC(rc);
325 
326  m0_cob_nsrec_init(&nsrec);
327  nsrec.cnr_fid = cob->co_nsrec.cnr_fid;
328  nsrec.cnr_linkno = cob->co_nsrec.cnr_cntr;
329 
330  rc = m0_cob_name_add(cob, nskey, &nsrec, tx);
331  m0_free(nskey);
332  if (rc != 0)
333  return M0_RC(rc);
334 
335  cob->co_nsrec.cnr_cntr++;
336  rc = m0_cob_update(cob, &cob->co_nsrec, NULL, NULL, tx);
337 
338  return M0_RC(rc);
339 }
340 
348 M0_INTERNAL int m0_mdstore_dir_empty_check(struct m0_mdstore *md,
349  struct m0_cob *cob)
350 {
351  struct m0_cob_iterator it;
352  struct m0_bitstring empty = {.b_len = 0};
353  int rc;
354 
355  M0_ENTRY();
357  if (rc != 0) {
358  M0_LOG(M0_DEBUG, "iterator init: %d", rc);
359  goto out;
360  }
362  if (rc == 0) {
363  M0_LOG(M0_DEBUG, FID_F"/%.*s contains "FID_F"/%.*s",
367  FID_P(&it.ci_key->cnk_pfid),
368  m0_bitstring_len_get(&it.ci_key->cnk_name),
369  (char *)m0_bitstring_buf_get(&it.ci_key->cnk_name));
370  rc = -ENOTEMPTY;
371  } else if (rc == -ENOENT)
372  rc = 0;
374 out:
375  M0_LEAVE("rc: %d", rc);
376  return M0_RC(rc);
377 }
378 
379 M0_INTERNAL void
381  struct m0_be_tx_credit *accum)
382 {
386 }
387 
388 M0_INTERNAL int m0_mdstore_unlink(struct m0_mdstore *md,
389  struct m0_fid *pfid,
390  struct m0_cob *cob,
391  struct m0_buf *name,
392  struct m0_be_tx *tx)
393 {
394  struct m0_cob *ncob;
395  struct m0_cob_nskey *nskey = NULL;
396  struct m0_cob_oikey oikey;
397  time_t now;
398  int rc;
399 
400  M0_ENTRY(FID_F"/%.*s", FID_P(pfid),
401  (int)name->b_nob, (char *)name->b_addr);
402  M0_ASSERT(pfid != NULL);
403  M0_ASSERT(cob != NULL);
404  M0_LOG(M0_DEBUG, FID_F"/%.*s->"FID_F",%d cob",
409 
410  /* We don't allow unlink in .motr and .motr/fid directories. */
411  if (m0_fid_cmp(pfid, &M0_MDSERVICE_SLASH_FID) < 0) {
412  rc = -EOPNOTSUPP;
413  goto out;
414  }
415 
416  /* We don't allow to kill .motr dir. */
417  if (m0_fid_eq(pfid, &M0_MDSERVICE_SLASH_FID) &&
418  name->b_nob == strlen(M0_DOT_MOTR_NAME) &&
419  !strncmp((char *)name->b_addr, M0_DOT_MOTR_NAME, (int)name->b_nob)) {
420  rc = -EOPNOTSUPP;
421  goto out;
422  }
423 
425 
426  time(&now);
427 
428  /*
429  * Check for hardlinks.
430  */
431  if (!S_ISDIR(cob->co_omgrec.cor_mode)) {
432  /*
433  * New stat data name should get updated nlink value.
434  */
436 
437  rc = m0_cob_nskey_make(&nskey, pfid, (char *)name->b_addr,
438  name->b_nob);
439  if (rc != 0) {
440  M0_LOG(M0_DEBUG, "m0_mdstore_unlink(): nskey make "
441  "failed with %d", rc);
442  goto out;
443  }
444 
445  /*
446  * Check if we're trying to kill stata data entry. We need to
447  * move stat data to another name if so.
448  */
449  if (cob->co_nsrec.cnr_nlink > 0) {
450  M0_LOG(M0_DEBUG, "m0_mdstore_unlink(): more links exist");
451  if (m0_cob_nskey_cmp(nskey, cob->co_nskey) == 0) {
452  M0_LOG(M0_DEBUG, "m0_mdstore_unlink(): unlink statdata "
453  "name, find new statdata with %d or more nlinks",
454  cob->co_nsrec.cnr_linkno + 1);
455 
456  /*
457  * Find another name (new stat data) in object index to
458  * move old statdata to it.
459  */
461  cob->co_nsrec.cnr_linkno + 1);
462 
463  rc = m0_cob_locate(md->md_dom, &oikey, 0, &ncob);
464  if (rc != 0) {
465  M0_LOG(M0_DEBUG, "m0_mdstore_unlink(): locate "
466  "failed with %d", rc);
467  m0_free(nskey);
468  goto out;
469  }
470  M0_LOG(M0_DEBUG, "m0_mdstore_unlink(): locate found "
471  "name with %d nlinks", ncob->co_oikey.cok_linkno);
473  } else {
474  M0_LOG(M0_DEBUG, "m0_mdstore_unlink(): unlink hardlink "
475  "name");
476  ncob = cob;
477  }
478 
479  M0_LOG(M0_DEBUG, "m0_mdstore_unlink(): update statdata on store");
480 
485  rc = m0_cob_update(ncob, &cob->co_nsrec, NULL, NULL, tx);
486  if (rc != 0) {
487  M0_LOG(M0_DEBUG, "m0_mdstore_unlink(): new statdata "
488  "update failed with %d", rc);
489  m0_free(nskey);
490  goto out;
491  }
492 
494  rc = m0_cob_name_del(cob, nskey, tx);
495  if (rc != 0) {
496  M0_LOG(M0_DEBUG, "m0_mdstore_unlink(): name del "
497  "failed with %d", rc);
498  m0_free(nskey);
499  goto out;
500  }
501  } else {
502  /* Zero nlink reached, kill entire object. */
503  rc = m0_cob_delete(cob, tx);
504  }
505  m0_free(nskey);
506  } else {
507  /*
508  * TODO: we must take some sort of a lock
509  * when doing check-before-modify update to directory.
510  */
512  if (rc != 0)
513  goto out;
514  rc = m0_cob_delete(cob, tx);
515  if (rc != 0)
516  goto out;
518  rc = m0_mdstore_dir_nlink_update(md, pfid, -1, tx);
519  }
520 
521 out:
522  return M0_RC(rc);
523 }
524 
525 M0_INTERNAL int m0_mdstore_open(struct m0_mdstore *md,
526  struct m0_cob *cob,
528  struct m0_be_tx *tx)
529 {
533  return M0_RC(0);
534 }
535 
536 M0_INTERNAL int m0_mdstore_close(struct m0_mdstore *md,
537  struct m0_cob *cob,
538  struct m0_be_tx *tx)
539 {
540  int rc = 0;
541 
542  M0_ASSERT(cob != NULL);
543 
549  return M0_RC(rc);
550 }
551 
552 M0_INTERNAL void
554  struct m0_be_tx_credit *accum)
555 {
558 }
559 
560 M0_INTERNAL int m0_mdstore_rename(struct m0_mdstore *md,
561  struct m0_fid *pfid_tgt,
562  struct m0_fid *pfid_src,
563  struct m0_cob *cob_tgt,
564  struct m0_cob *cob_src,
565  struct m0_buf *tname,
566  struct m0_buf *sname,
567  struct m0_be_tx *tx)
568 {
569  struct m0_cob_nskey *srckey = NULL;
570  struct m0_cob_nskey *tgtkey = NULL;
571  struct m0_cob *tncob = NULL;
572  bool unlink;
573  time_t now;
574  int rc;
575 
576  M0_ENTRY();
577  M0_ASSERT(pfid_tgt != NULL);
578  M0_ASSERT(pfid_src != NULL);
579 
580  time(&now);
581 
582  /* We don't allow rename in/with .motr/fid directories. */
583  if (m0_fid_cmp(pfid_tgt, &M0_MDSERVICE_SLASH_FID) < 0 ||
584  m0_fid_cmp(pfid_src, &M0_MDSERVICE_SLASH_FID) < 0 ||
585  m0_fid_cmp(m0_cob_fid(cob_tgt), &M0_MDSERVICE_SLASH_FID) < 0 ||
586  m0_fid_cmp(m0_cob_fid(cob_src), &M0_MDSERVICE_SLASH_FID) < 0) {
587  rc = -EOPNOTSUPP;
588  goto out;
589  }
590 
591  /*
592  * Let's kill existing target name.
593  */
594  rc = m0_mdstore_lookup(md, pfid_tgt, tname, &tncob);
595  unlink = (tncob != NULL &&
596  m0_cob_nskey_cmp(tncob->co_nskey, cob_tgt->co_nskey) != 0);
597 
598  if (!m0_fid_eq(m0_cob_fid(cob_tgt), m0_cob_fid(cob_src)) || unlink) {
599  rc = m0_mdstore_unlink(md, pfid_tgt, cob_tgt, tname, tx);
600  if (rc != 0) {
601  if (tncob)
602  m0_cob_put(tncob);
603  goto out;
604  }
605  }
606  if (tncob)
607  m0_cob_put(tncob);
608  /*
609  * Prepare src and dst keys.
610  */
611  m0_cob_nskey_make(&srckey, pfid_src,
612  (char *)sname->b_addr, sname->b_nob);
613  m0_cob_nskey_make(&tgtkey, pfid_tgt,
614  (char *)tname->b_addr, tname->b_nob);
615 
616  rc = m0_cob_name_update(cob_src, srckey, tgtkey, tx);
617 
618  m0_free(srckey);
619  m0_free(tgtkey);
620 out:
621  M0_LEAVE("rc: %d", rc);
622  return M0_RC(rc);
623 }
624 
625 M0_INTERNAL void
627  struct m0_be_tx_credit *accum)
628 {
630 }
631 
632 M0_INTERNAL int m0_mdstore_setattr(struct m0_mdstore *md,
633  struct m0_cob *cob,
634  struct m0_cob_attr *attr,
635  struct m0_be_tx *tx)
636 {
637  M0_ENTRY();
638  M0_ASSERT(cob != NULL);
639  return M0_RC(m0_cob_setattr(cob, attr, tx));
640 }
641 
642 M0_INTERNAL int m0_mdstore_getattr(struct m0_mdstore *md,
643  struct m0_cob *cob,
644  struct m0_cob_attr *attr)
645 {
646  int rc = 0;
647 
648  M0_ENTRY();
649  M0_ASSERT(cob != NULL);
650 
651  M0_SET0(attr);
652  attr->ca_valid = 0;
653  attr->ca_tfid = cob->co_nsrec.cnr_fid;
654  attr->ca_pfid = cob->co_nskey->cnk_pfid;
655 
656  /*
657  * Copy permissions and owner info into rep.
658  */
659  if (cob->co_flags & M0_CA_OMGREC) {
660  attr->ca_valid |= M0_COB_UID | M0_COB_GID | M0_COB_MODE;
661  attr->ca_uid = cob->co_omgrec.cor_uid;
662  attr->ca_gid = cob->co_omgrec.cor_gid;
663  attr->ca_mode = cob->co_omgrec.cor_mode;
664  }
665 
666  /*
667  * Copy nsrec fields into response.
668  */
669  if (cob->co_flags & M0_CA_NSREC) {
670  attr->ca_valid |= M0_COB_ATIME | M0_COB_CTIME | M0_COB_MTIME |
672  M0_COB_RDEV*/ | M0_COB_LID | M0_COB_PVER;
673 
674  attr->ca_atime = cob->co_nsrec.cnr_atime;
675  attr->ca_ctime = cob->co_nsrec.cnr_ctime;
676  attr->ca_mtime = cob->co_nsrec.cnr_mtime;
677  attr->ca_blksize = cob->co_nsrec.cnr_blksize;
678  attr->ca_blocks = cob->co_nsrec.cnr_blocks;
679  attr->ca_nlink = cob->co_nsrec.cnr_nlink;
680  //attr->ca_rdev = cob->co_nsrec.cnr_rdev;
681  attr->ca_size = cob->co_nsrec.cnr_size;
682  attr->ca_lid = cob->co_nsrec.cnr_lid;
683  attr->ca_pver = cob->co_nsrec.cnr_pver;
684  //attr->ca_version = cob->co_nsrec.cnr_version;
685  M0_LOG(M0_DEBUG, "attrs of "FID_F"/%.*s->"FID_F",%u: "
686  "cntr:%u, nlink:%u",
687  FID_P(&attr->ca_pfid),
690  FID_P(&attr->ca_tfid),
691  (unsigned)cob->co_nsrec.cnr_linkno,
692  (unsigned)cob->co_nsrec.cnr_cntr,
693  (unsigned)attr->ca_nlink);
694  M0_LOG(M0_DEBUG, "size:%u, lid:%u",
695  (unsigned)attr->ca_size,
696  (unsigned)attr->ca_lid);
697  }
698 
699  /*
700  * @todo: Copy rest of the fab fields.
701  */
702  return M0_RC(rc);
703 }
704 
705 M0_INTERNAL int m0_mdstore_readdir(struct m0_mdstore *md,
706  struct m0_cob *cob,
707  struct m0_rdpg *rdpg)
708 {
709  struct m0_cob_iterator it;
710  struct m0_dirent *ent;
711  struct m0_dirent *last = NULL;
712  int nob;
713  int reclen;
714  int rc;
715  int dot;
716  char *s_buf;
717  uint32_t s_len;
718  struct m0_bitstring empty = {.b_len = 0};
719  struct m0_bitstring *pos;
720 
721  M0_ENTRY();
722  M0_ASSERT(cob != NULL && rdpg != NULL);
723 
724  pos = rdpg->r_pos;
725  s_buf = (char *)m0_bitstring_buf_get(pos);
727 
728  M0_LOG(M0_DEBUG, "Readdir on object "FID_F" starting from \"%.*s\"",
730 
731  ent = rdpg->r_buf.b_addr;
732  nob = rdpg->r_buf.b_nob;
733  if (nob < sizeof(struct m0_dirent)) {
734  rc = -EINVAL;
735  goto out_end;
736  }
737 
738  /* Emulate "." and ".." entries at the 1st and 2nd positions. */
739  if (s_len == 1 && s_buf[0] == '.') {
740  dot = 1;
741  } else if (s_len == 2 && strncmp(s_buf, "..", 2) == 0) {
742  dot = 2;
743  } else {
744  dot = 0;
745  }
746 
747  rc = m0_cob_iterator_init(cob, &it, dot ? &empty : pos);
748  if (rc != 0) {
749  M0_LOG(M0_DEBUG, "Iterator failed to position with %d", rc);
750  goto out;
751  }
752 
753  /*
754  * Positions iterator to the closest key greater or equal
755  * to the starting position. Returns -ENOENT if no such
756  * key exists.
757  */
759  while (rc == 0 || dot) {
760  if (dot == 1) {
761  /* pos already contains "." */
762  } else if (dot == 2) {
763  m0_bitstring_copy(pos, "..", 2);
764  } else {
765  s_buf = m0_bitstring_buf_get(&it.ci_key->cnk_name);
766  s_len = m0_bitstring_len_get(&it.ci_key->cnk_name);
767  /* pos was allocated with large buffer:
768  * rdpg.r_pos = m0_alloc(M0_MD_MAX_NAME_LEN) */
770  }
771 
772  reclen = m0_align(sizeof(*ent) + m0_bitstring_len_get(pos), 8);
773 
774  if (nob >= reclen) {
776  memcpy(ent->d_name, m0_bitstring_buf_get(pos),
777  ent->d_namelen);
778  ent->d_reclen = reclen;
780  "Readdir filled entry \"%.*s\" recsize %d",
781  ent->d_namelen, (char *)ent->d_name,
782  ent->d_reclen);
783  } else {
784  /*
785  * If buffer was too small to hold even one record,
786  * return -EINVAL. Otherwise return 0.
787  */
788  rc = last == NULL ? -EINVAL : 0;
789  goto out_end;
790  }
791  last = ent;
792  ent = (struct m0_dirent *)((char *)ent + reclen);
793  nob -= reclen;
794  if (!dot)
796  else if (++dot > 2)
797  dot = 0;
798  }
799 out_end:
801  if (last != NULL) {
802  last->d_reclen = 0; /* The last record indicator. */
803  s_buf = (char *)m0_bitstring_buf_get(pos);
806  M0_LOG(M0_DEBUG, "%s entry: \"%.*s\"", rc ? "last" : "next",
807  s_len, s_buf);
808  rc = rc ? ENOENT : 0;
809  }
810  if (rc == -ENOENT)
811  rc = ENOENT;
812 out:
813  return M0_RC(rc);
814 }
815 
819 M0_INTERNAL int m0_mdstore_locate(struct m0_mdstore *md,
820  const struct m0_fid *fid,
821  struct m0_cob **cob,
822  int flags)
823 {
824  struct m0_cob_oikey oikey;
825  int rc;
826 
827  M0_ENTRY(FID_F, FID_P(fid));
828  m0_cob_oikey_make(&oikey, fid, 0);
829 
830  if (flags == M0_MD_LOCATE_STORED) {
831  rc = m0_cob_locate(md->md_dom, &oikey,
833  } else {
834  /*
835  * @todo: locate cob in opened cobs table.
836  */
837  rc = -EOPNOTSUPP;
838  }
839  if (rc == 0) {
840  M0_LEAVE(FID_F"<-"FID_F"/%.*s",
841  FID_P(&(*cob)->co_nsrec.cnr_fid),
842  FID_P(&(*cob)->co_nskey->cnk_pfid),
843  m0_bitstring_len_get(&(*cob)->co_nskey->cnk_name),
844  (char *)m0_bitstring_buf_get(&(*cob)->co_nskey->cnk_name));
845  } else {
846  M0_LEAVE("rc: %d", rc);
847  }
848  return M0_RC(rc);
849 }
850 
863 M0_INTERNAL int m0_mdstore_lookup(struct m0_mdstore *md,
864  struct m0_fid *pfid,
865  struct m0_buf *name,
866  struct m0_cob **cob)
867 {
868  struct m0_cob_nskey *nskey = NULL;
869  struct m0_fid fid;
870  int flags;
871  int rc;
872 
873  M0_ENTRY();
874  if (pfid == NULL)
875  pfid = (struct m0_fid *)&M0_COB_ROOT_FID;
876 
877  /*
878  Check for obf case and use m0_cob_locate() to get cob by fid
879  extracted from name.
880  */
881  if (m0_fid_eq(pfid, &M0_DOT_MOTR_FID_FID)) {
882  rc = m0_fid_sscanf((char *)name->b_addr, &fid);
883  if (rc != 0)
884  goto out;
886  } else {
887  rc = m0_cob_nskey_make(&nskey, pfid, (char *)name->b_addr, name->b_nob);
888  if (rc != 0)
889  goto out;
891  rc = m0_cob_lookup(md->md_dom, nskey, flags, cob);
892  }
893 out:
894  return M0_RC(rc);
895 }
896 
897 #define MDSTORE_PATH_MAX 1024
898 #define MDSTORE_NAME_MAX 255
899 
900 M0_INTERNAL int m0_mdstore_path(struct m0_mdstore *md,
901  struct m0_fid *fid,
902  char **path)
903 {
904  struct m0_cob *cob;
905  struct m0_fid pfid;
906  int rc;
907 
908  M0_ENTRY(FID_F, FID_P(fid));
909  *path = m0_alloc(MDSTORE_PATH_MAX);
910  if (*path == NULL)
911  return M0_ERR(-ENOMEM);
912 
913 restart:
914  pfid = *fid;
915 
916  do {
917  char name[MDSTORE_NAME_MAX] = {0,};
918 
920  if (rc != 0)
921  goto out;
922 
924  strncat(name,
927  }
928  if (!m0_fid_eq(m0_cob_fid(cob), fid) ||
930  strcat(name, "/");
931  memmove(*path + strlen(name), *path, strlen(*path));
932  memcpy(*path, name, strlen(name));
933  pfid = cob->co_nskey->cnk_pfid;
934  m0_cob_put(cob);
935  } while (!m0_fid_eq(&pfid, &M0_COB_ROOT_FID));
936 out:
937  if (rc == -EDEADLK) {
938  memset(*path, 0, MDSTORE_PATH_MAX);
939  goto restart;
940  }
941  if (rc != 0)
942  m0_free0(path);
943  M0_LEAVE("rc: %d, path: %s", rc, *path);
944  return M0_RC(rc);
945 }
946 
947 #undef M0_TRACE_SUBSYSTEM
948 
949 /*
950  * Local variables:
951  * c-indentation-style: "K&R"
952  * c-basic-offset: 8
953  * tab-width: 8
954  * fill-column: 80
955  * scroll-step: 1
956  * End:
957  */
struct m0_cob_nsrec co_nsrec
Definition: cob.h:590
uint8_t * s_buf
Definition: string.h:100
M0_INTERNAL void m0_mdstore_fini(struct m0_mdstore *md)
Definition: mdstore.c:130
char d_name[0]
Definition: cob.h:601
uint64_t cnr_mtime
Definition: cob.h:435
#define M0_PRE(cond)
uint32_t cnr_nlink
Definition: cob.h:426
Definition: cob.h:581
struct m0_cob_domain * md_dom
Definition: mdstore.h:58
uint64_t cnr_size
Definition: cob.h:430
int const char const void size_t int flags
Definition: dir.c:328
#define NULL
Definition: misc.h:38
uint64_t co_flags
Definition: cob.h:585
uint64_t cnr_blocks
Definition: cob.h:433
#define M0_MD_MAX_NAME_LEN
Definition: mdstore.h:43
M0_INTERNAL int m0_mdstore_init(struct m0_mdstore *md, struct m0_be_seg *db, bool init_root)
Definition: mdstore.c:78
void * b_addr
Definition: buf.h:39
uint32_t s_len
Definition: string.h:99
M0_INTERNAL int m0_mdstore_dir_empty_check(struct m0_mdstore *md, struct m0_cob *cob)
Definition: mdstore.c:348
M0_INTERNAL void m0_cob_iterator_fini(struct m0_cob_iterator *it)
Definition: cob.c:1477
static void mdstore_fini(struct m0_mdstore *md, bool pre_destroy)
Definition: mdstore.c:117
M0_INTERNAL int m0_cob_alloc_omgid(struct m0_cob_domain *dom, uint64_t *omgid)
Definition: cob.c:1634
M0_INTERNAL int m0_cob_nskey_cmp(const struct m0_cob_nskey *k0, const struct m0_cob_nskey *k1)
Definition: cob.c:163
#define M0_LOG(level,...)
Definition: trace.h:167
M0_LEAVE()
M0_INTERNAL int m0_mdstore_locate(struct m0_mdstore *md, const struct m0_fid *fid, struct m0_cob **cob, int flags)
Definition: mdstore.c:819
Definition: cob.h:598
uint64_t cnr_blksize
Definition: cob.h:432
uint64_t sf_files
Definition: mdstore.h:51
void m0_cob_domain_fini(struct m0_cob_domain *dom)
Definition: cob.c:726
M0_INTERNAL uint32_t m0_bitstring_len_get(const struct m0_bitstring *c)
Definition: bitstring.c:38
M0_INTERNAL void m0_buf_init(struct m0_buf *buf, void *data, uint32_t nob)
Definition: buf.c:37
M0_INTERNAL int m0_mdstore_statfs(struct m0_mdstore *md, struct m0_statfs *statfs)
Definition: mdstore.c:55
#define MDSTORE_PATH_MAX
Definition: mdstore.c:897
M0_INTERNAL void m0_cob_put(struct m0_cob *cob)
Definition: cob.c:1095
static struct m0_be_emap_cursor it
Definition: extmap.c:46
uint32_t sf_bsize
Definition: mdstore.h:47
M0_INTERNAL const struct m0_fid M0_DOT_MOTR_FID_FID
Definition: md_fid.c:53
uint64_t cnr_atime
Definition: cob.h:434
int m0_cob_domain_create(struct m0_cob_domain **dom, struct m0_sm_group *grp, const struct m0_cob_domain_id *cdid, struct m0_be_domain *bedom, struct m0_be_seg *seg)
Definition: cob.c:840
M0_INTERNAL int m0_cob_fabrec_make(struct m0_cob_fabrec **rech, const char *link, size_t linklen)
Definition: cob.c:262
#define M0_SET0(obj)
Definition: misc.h:64
M0_INTERNAL int m0_fid_cmp(const struct m0_fid *fid0, const struct m0_fid *fid1)
Definition: fid.c:170
M0_INTERNAL bool m0_fid_is_set(const struct m0_fid *fid)
Definition: fid.c:106
M0_INTERNAL int m0_cob_name_update(struct m0_cob *cob, struct m0_cob_nskey *srckey, struct m0_cob_nskey *tgtkey, struct m0_be_tx *tx)
Definition: cob.c:2004
#define MDSTORE_NAME_MAX
Definition: mdstore.c:898
uint32_t cnr_cntr
Definition: cob.h:427
M0_INTERNAL int m0_cob_nskey_make(struct m0_cob_nskey **keyh, const struct m0_fid *pfid, const char *name, size_t namelen)
Definition: cob.c:148
M0_INTERNAL int m0_mdstore_close(struct m0_mdstore *md, struct m0_cob *cob, struct m0_be_tx *tx)
Definition: mdstore.c:536
struct m0_fid fid
Definition: di.c:46
M0_INTERNAL int m0_mdstore_fcreate(struct m0_mdstore *md, struct m0_fid *pfid, struct m0_cob_attr *attr, struct m0_cob **out, struct m0_be_tx *tx)
Definition: mdstore.c:209
return M0_RC(rc)
M0_INTERNAL void m0_cob_tx_credit(struct m0_cob_domain *dom, enum m0_cob_op optype, struct m0_be_tx_credit *accum)
Definition: cob.c:2281
M0_INTERNAL void m0_mdstore_unlink_credit(struct m0_mdstore *md, struct m0_be_tx_credit *accum)
Definition: mdstore.c:380
#define M0_ENTRY(...)
Definition: trace.h:170
struct m0_cob_nskey * co_nskey
Definition: cob.h:588
Definition: buf.h:37
uint32_t cnr_linkno
Definition: cob.h:420
M0_INTERNAL int m0_mdstore_link(struct m0_mdstore *md, struct m0_fid *pfid, struct m0_cob *cob, struct m0_buf *name, struct m0_be_tx *tx)
Definition: mdstore.c:295
M0_INTERNAL void m0_mdstore_create_credit(struct m0_mdstore *md, struct m0_be_tx_credit *accum)
Definition: mdstore.c:202
return M0_ERR(-EOPNOTSUPP)
M0_INTERNAL const struct m0_fid M0_MDSERVICE_SLASH_FID
Definition: md_fid.c:63
uint32_t cok_linkno
Definition: cob.h:458
uint32_t d_namelen
Definition: cob.h:599
M0_INTERNAL int m0_cob_iterator_next(struct m0_cob_iterator *it)
Definition: cob.c:1512
M0_INTERNAL const char M0_DOT_MOTR_NAME[]
Definition: md_fid.c:51
const char * name
Definition: trace.c:110
static void attr(struct m0_addb2__context *ctx, const uint64_t *v, char *buf)
Definition: dump.c:949
M0_INTERNAL void m0_bitstring_copy(struct m0_bitstring *dst, const char *src, size_t count)
Definition: bitstring.c:63
struct m0_bitstring * r_pos
Definition: cob.h:608
M0_INTERNAL struct m0_bitstring * m0_bitstring_alloc(const char *name, size_t len)
Definition: bitstring.c:48
M0_INTERNAL int m0_cob_name_add(struct m0_cob *cob, struct m0_cob_nskey *nskey, struct m0_cob_nsrec *nsrec, struct m0_be_tx *tx)
Definition: cob.c:1924
uint64_t sf_bfree
Definition: mdstore.h:49
#define m0_free0(pptr)
Definition: memory.h:77
m0_bcount_t b_nob
Definition: buf.h:38
static struct m0_cob * cob
Definition: bytecount.c:40
#define M0_ASSERT(cond)
struct m0_bitstring cnk_name
Definition: cob.h:392
uint32_t d_reclen
Definition: cob.h:600
M0_INTERNAL void m0_cob_nsrec_init(struct m0_cob_nsrec *nsrec)
Definition: cob.c:2058
int m0_cob_domain_destroy(struct m0_cob_domain *dom, struct m0_sm_group *grp, struct m0_be_domain *bedom)
Definition: cob.c:871
uint32_t sf_namelen
Definition: mdstore.h:53
M0_INTERNAL void m0_cob_oikey_make(struct m0_cob_oikey *oikey, const struct m0_fid *fid, int linkno)
Definition: cob.c:141
uint64_t sf_ffree
Definition: mdstore.h:52
M0_INTERNAL int m0_cob_create(struct m0_cob *cob, struct m0_cob_nskey *nskey, struct m0_cob_nsrec *nsrec, struct m0_cob_fabrec *fabrec, struct m0_cob_omgrec *omgrec, struct m0_be_tx *tx)
Definition: cob.c:1681
uint32_t cor_mode
Definition: cob.h:498
uint64_t sf_blocks
Definition: mdstore.h:48
void * m0_alloc(size_t size)
Definition: memory.c:126
M0_INTERNAL int m0_mdstore_open(struct m0_mdstore *md, struct m0_cob *cob, m0_mdstore_locate_flags_t flags, struct m0_be_tx *tx)
Definition: mdstore.c:525
uint32_t cor_uid
Definition: cob.h:497
static struct m0_sm_group * grp
Definition: mdstore.c:50
M0_INTERNAL int m0_mdstore_mod_init(void)
Definition: mdstore.c:41
struct m0_cob_oikey co_oikey
Definition: cob.h:589
M0_INTERNAL int m0_cob_lookup(struct m0_cob_domain *dom, struct m0_cob_nskey *nskey, uint64_t flags, struct m0_cob **out)
Definition: cob.c:1371
M0_INTERNAL void m0_mdstore_dir_nlink_update_credit(struct m0_mdstore *md, struct m0_be_tx_credit *accum)
Definition: mdstore.c:161
M0_INTERNAL int m0_mdstore_readdir(struct m0_mdstore *md, struct m0_cob *cob, struct m0_rdpg *rdpg)
Definition: mdstore.c:705
M0_INTERNAL int m0_fid_sscanf(const char *s, struct m0_fid *fid)
Definition: fid.c:227
Definition: seg.h:66
#define FID_P(f)
Definition: fid.h:77
struct m0_fid sf_root
Definition: mdstore.h:54
int m0_cob_domain_init(struct m0_cob_domain *dom, struct m0_be_seg *seg)
Definition: cob.c:708
M0_INTERNAL void m0_mdstore_mod_fini(void)
Definition: mdstore.c:46
M0_INTERNAL int m0_mdstore_path(struct m0_mdstore *md, struct m0_fid *fid, char **path)
Definition: mdstore.c:900
M0_INTERNAL int m0_mdstore_rename(struct m0_mdstore *md, struct m0_fid *pfid_tgt, struct m0_fid *pfid_src, struct m0_cob *cob_tgt, struct m0_cob *cob_src, struct m0_buf *tname, struct m0_buf *sname, struct m0_be_tx *tx)
Definition: mdstore.c:560
M0_INTERNAL bool m0_fid_eq(const struct m0_fid *fid0, const struct m0_fid *fid1)
Definition: fid.c:164
static struct m0_mdstore md
Definition: mdstore.c:54
struct m0_fid cnr_pver
Definition: cob.h:438
struct m0_cob * md_root
Definition: mdstore.h:59
M0_INTERNAL void m0_mdstore_rename_credit(struct m0_mdstore *md, struct m0_be_tx_credit *accum)
Definition: mdstore.c:553
Definition: fid.h:38
M0_INTERNAL int m0_mdstore_create(struct m0_mdstore *md, struct m0_sm_group *grp, struct m0_cob_domain_id *id, struct m0_be_domain *bedom, struct m0_be_seg *db)
Definition: mdstore.c:135
M0_INTERNAL void m0_mdstore_setattr_credit(struct m0_mdstore *md, struct m0_be_tx_credit *accum)
Definition: mdstore.c:626
struct m0_buf r_buf
Definition: cob.h:609
M0_INTERNAL int m0_mdstore_unlink(struct m0_mdstore *md, struct m0_fid *pfid, struct m0_cob *cob, struct m0_buf *name, struct m0_be_tx *tx)
Definition: mdstore.c:388
M0_INTERNAL void * m0_bitstring_buf_get(struct m0_bitstring *c)
Definition: bitstring.c:33
M0_INTERNAL const char M0_COB_ROOT_NAME[]
Definition: md_fid.c:44
enum m0_mdstore_locate_flags m0_mdstore_locate_flags_t
Definition: mdstore.h:75
#define M0_MD_FAKE_BLOCKSIZE
Definition: mdstore.c:52
struct m0_cob_omgrec co_omgrec
Definition: cob.h:592
M0_INTERNAL int m0_cob_update(struct m0_cob *cob, struct m0_cob_nsrec *nsrec, struct m0_cob_fabrec *fabrec, struct m0_cob_omgrec *omgrec, struct m0_be_tx *tx)
Definition: cob.c:1860
Definition: cob.h:607
uint64_t sf_bavail
Definition: mdstore.h:50
M0_INTERNAL int m0_cob_delete(struct m0_cob *cob, struct m0_be_tx *tx)
Definition: cob.c:1789
M0_INTERNAL void m0_mdstore_link_credit(struct m0_mdstore *md, struct m0_be_tx_credit *accum)
Definition: mdstore.c:288
M0_INTERNAL int m0_cob_iterator_get(struct m0_cob_iterator *it)
Definition: cob.c:1483
M0_INTERNAL int m0_cob_locate(struct m0_cob_domain *dom, struct m0_cob_oikey *oikey, uint64_t flags, struct m0_cob **out)
Definition: cob.c:1407
M0_INTERNAL int m0_cob_setattr(struct m0_cob *cob, struct m0_cob_attr *attr, struct m0_be_tx *tx)
Definition: cob.c:2068
static void restart(void)
Definition: service_ut.c:312
M0_INTERNAL int m0_mdstore_destroy(struct m0_mdstore *md, struct m0_sm_group *grp, struct m0_be_domain *bedom)
Definition: mdstore.c:146
M0_INTERNAL int m0_cob_name_del(struct m0_cob *cob, struct m0_cob_nskey *nskey, struct m0_be_tx *tx)
Definition: cob.c:1966
M0_INTERNAL int m0_mdstore_setattr(struct m0_mdstore *md, struct m0_cob *cob, struct m0_cob_attr *attr, struct m0_be_tx *tx)
Definition: mdstore.c:632
M0_INTERNAL int m0_cob_alloc(struct m0_cob_domain *dom, struct m0_cob **out)
Definition: cob.c:1100
#define out(...)
Definition: gen.c:41
uint32_t cor_gid
Definition: cob.h:499
M0_INTERNAL const struct m0_fid * m0_cob_fid(const struct m0_cob *cob)
Definition: cob.c:122
struct m0_dirent * ent
Definition: dir.c:1029
M0_INTERNAL int m0_mdstore_lookup(struct m0_mdstore *md, struct m0_fid *pfid, struct m0_buf *name, struct m0_cob **cob)
Definition: mdstore.c:863
struct m0_bitstring * r_end
Definition: cob.h:610
M0_INTERNAL int m0_mdstore_dir_nlink_update(struct m0_mdstore *md, struct m0_fid *fid, int inc, struct m0_be_tx *tx)
Definition: mdstore.c:167
uint64_t cnr_ctime
Definition: cob.h:436
void m0_free(void *data)
Definition: memory.c:146
M0_INTERNAL int m0_mdstore_getattr(struct m0_mdstore *md, struct m0_cob *cob, struct m0_cob_attr *attr)
Definition: mdstore.c:642
int32_t rc
Definition: trigger_fop.h:47
#define M0_MD_FAKE_VOLUME
Definition: mdstore.c:53
struct m0_fid cnk_pfid
Definition: cob.h:391
static uint64_t m0_align(uint64_t val, uint64_t alignment)
Definition: arith.h:170
uint64_t sf_type
Definition: mdstore.h:46
M0_INTERNAL int m0_cob_iterator_init(struct m0_cob *cob, struct m0_cob_iterator *it, struct m0_bitstring *name)
Definition: cob.c:1457
static void empty(void)
Definition: consumer.c:101
M0_INTERNAL const struct m0_fid M0_COB_ROOT_FID
Definition: md_fid.c:39
static struct m0_addb2_frame_header last
Definition: storage.c:93
uint64_t cnr_lid
Definition: cob.h:437
#define FID_F
Definition: fid.h:75
Definition: tx.h:280
struct m0_fid cnr_fid
Definition: cob.h:419