int pfl_odt_create(const char *fn, int64_t nitems, size_t itemsz, int overwrite, size_t startoff, size_t pad, int tflg) { int rc; int64_t item; struct pfl_odt_slotftr f; struct pfl_odt_hdr *h; struct pfl_odt *t; t = PSCALLOC(sizeof(*t)); t->odt_ops = pfl_odtops; INIT_SPINLOCK(&t->odt_lock); snprintf(t->odt_name, sizeof(t->odt_name), "%s", pfl_basename(fn)); t->odt_iostats.rd = pfl_opstat_init("odt-%s-rd", t->odt_name); t->odt_iostats.wr = pfl_opstat_init("odt-%s-wr", t->odt_name); h = PSCALLOC(sizeof(*h)); memset(h, 0, sizeof(*h)); h->odth_nitems = nitems; h->odth_itemsz = itemsz; h->odth_slotsz = itemsz + pad + sizeof(f); h->odth_options = tflg; h->odth_start = startoff; t->odt_hdr = h; psc_crc64_calc(&h->odth_crc, h, sizeof(*h) - sizeof(h->odth_crc)); /* pfl_odt_new() and slm_odt_new() */ rc = t->odt_ops.odtop_new(t, fn, overwrite); if (rc) return (rc); for (item = 0; item < nitems; item++) _pfl_odt_doput(t, item, NULL, &f, 0); PFLOG_ODT(PLL_DIAG, t, "created"); pfl_odt_release(t); return (0); }
/* * Traverse a file hierarchy and perform an operation on each file * system entry. * @fn: file root. * @flags: behavorial flags. * @cmpf: optional dirent comparator for ordering. * @cbf: callback to invoke on each file. * @arg: optional argument to supply to callback. * Notes: the callback will be invoked with a fully resolved absolute * path name unless the file in question is a symbolic link. */ int pfl_filewalk(const char *fn, int flags, void *cmpf, int (*cbf)(FTSENT *, void *), void *arg) { char * const pathv[] = { (char *)fn, NULL }; int rc = 0, f_flags = 0; struct stat stb; FTSENT *f; FTS *fp; if (flags & PFL_FILEWALKF_RECURSIVE) { if (flags & PFL_FILEWALKF_NOSTAT) f_flags |= FTS_NOSTAT; if (flags & PFL_FILEWALKF_NOCHDIR) f_flags |= FTS_NOCHDIR; fp = pfl_fts_open(pathv, f_flags | FTS_COMFOLLOW | FTS_PHYSICAL, cmpf); if (fp == NULL) psc_fatal("fts_open %s", fn); while ((f = pfl_fts_read(fp)) != NULL) { switch (f->fts_info) { case FTS_NS: psclog_warnx("%s: %s", f->fts_path, strerror(f->fts_errno)); break; case FTS_F: case FTS_D: case FTS_SL: if (flags & PFL_FILEWALKF_VERBOSE) warnx("processing %s%s", fn, f->fts_info == FTS_D ? "/" : ""); case FTS_DP: rc = cbf(f, arg); if (rc) { pfl_fts_close(fp); return (rc); } break; default: if (f->fts_errno == 0) f->fts_errno = EOPNOTSUPP; psclog_warnx("%s: %s", f->fts_path, strerror(f->fts_errno)); break; } } pfl_fts_close(fp); } else { const char *basefn; size_t baselen; if (lstat(fn, &stb) == -1) err(1, "%s", fn); basefn = pfl_basename(fn); baselen = strlen(basefn); f = PSCALLOC(sizeof(*f) + baselen); f->fts_accpath = (char *)fn; f->fts_path = (char *)fn; f->fts_pathlen = strlen(fn); strlcpy(f->fts_name, basefn, baselen + 1); f->fts_namelen = baselen; f->fts_ino = stb.st_ino; f->fts_statp = &stb; switch (stb.st_mode & S_IFMT) { case S_IFDIR: f->fts_info = FTS_D; break; case S_IFREG: f->fts_info = FTS_F; break; case S_IFLNK: f->fts_info = FTS_SL; break; case S_IFBLK: f->fts_info = FTS_DEFAULT; break; default: psclog_warnx("%s: %s", fn, strerror(EOPNOTSUPP)); break; } rc = cbf(f, arg); PSCFREE(f); } return (rc); }
/** * pjournal_dump - Dump the contents of a journal file. * @fn: journal filename to query. * @verbose: whether to report stats summary or full dump. * * Each time mds restarts, it writes log entries starting from the very * first slot of the log. Anyway, the function dumps all log entries, * some of them may be from previous incarnations of the MDS. */ void pjournal_dump(const char *fn) { int i, ntotal, nmagic, nchksum, nformat, ndump, first = 1; uint32_t slot, highest_slot = -1, lowest_slot = -1; uint64_t chksum, highest_xid = 0, lowest_xid = 0; struct psc_journal_enthdr *pje; struct psc_journal_hdr *pjh; struct psc_journal *pj; struct stat statbuf; unsigned char *jbuf; ssize_t nb, pjhlen; time_t ts; ntotal = nmagic = nchksum = nformat = ndump = 0; pj = PSCALLOC(sizeof(*pj)); strlcpy(pj->pj_name, pfl_basename(fn), sizeof(pj->pj_name)); pj->pj_fd = open(fn, O_RDWR | O_DIRECT); if (pj->pj_fd == -1) psc_fatal("failed to open journal %s", fn); if (fstat(pj->pj_fd, &statbuf) == -1) psc_fatal("failed to stat journal %s", fn); /* * O_DIRECT may impose alignment restrictions so align the * buffer and perform I/O in multiples of file system block * size. */ pjhlen = PSC_ALIGN(sizeof(*pjh), statbuf.st_blksize); pjh = psc_alloc(pjhlen, PAF_PAGEALIGN); nb = pread(pj->pj_fd, pjh, pjhlen, 0); if (nb != pjhlen) psc_fatal("failed to read journal header"); pj->pj_hdr = pjh; if (pjh->pjh_magic != PJH_MAGIC) psc_fatalx("journal header has a bad magic number " "%#"PRIx64, pjh->pjh_magic); if (pjh->pjh_version != PJH_VERSION) psc_fatalx("journal header has an invalid version " "number %d", pjh->pjh_version); psc_crc64_init(&chksum); psc_crc64_add(&chksum, pjh, offsetof(struct psc_journal_hdr, pjh_chksum)); psc_crc64_fini(&chksum); if (pjh->pjh_chksum != chksum) psc_fatalx("journal header has an invalid checksum " "value %"PSCPRIxCRC64" vs %"PSCPRIxCRC64, pjh->pjh_chksum, chksum); if (S_ISREG(statbuf.st_mode) && statbuf.st_size != (off_t)(pjhlen + pjh->pjh_nents * PJ_PJESZ(pj))) psc_fatalx("size of the journal log %"PSCPRIdOFFT"d does " "not match specs in its header", statbuf.st_size); if (pjh->pjh_nents % pjh->pjh_readsize) psc_fatalx("number of entries %d is not a multiple of the " "readsize %d", pjh->pjh_nents, pjh->pjh_readsize); ts = pjh->pjh_timestamp; printf("%s:\n" " version: %u\n" " entry size: %u\n" " number of entries: %u\n" " batch read size: %u\n" " entry start offset: %"PRId64"\n" " format time: %s" " uuid: %"PRIx64"\n" " %4s %3s %4s %4s %s\n", fn, pjh->pjh_version, PJ_PJESZ(pj), pjh->pjh_nents, pjh->pjh_readsize, pjh->pjh_start_off, ctime(&ts), pjh->pjh_fsuuid, "idx", "typ", "xid", "txg", "details"); jbuf = psc_alloc(PJ_PJESZ(pj) * pj->pj_hdr->pjh_readsize, PAF_PAGEALIGN); for (slot = 0; slot < pjh->pjh_nents; slot += pjh->pjh_readsize) { nb = pread(pj->pj_fd, jbuf, PJ_PJESZ(pj) * pjh->pjh_readsize, PJ_GETENTOFF(pj, slot)); if (nb != PJ_PJESZ(pj) * pjh->pjh_readsize) warn("failed to read %d log entries at slot %d", pjh->pjh_readsize, slot); for (i = 0; i < pjh->pjh_readsize; i++) { ntotal++; pje = (void *)&jbuf[PJ_PJESZ(pj) * i]; if (pje->pje_magic != PJE_MAGIC) { nmagic++; warnx("journal slot %d has a bad magic" "number", slot + i); continue; } /* * If we hit a new entry that is never used, we * assume that the rest of the journal is never * used. */ if (pje->pje_type == PJE_FORMAT) { nformat = nformat + pjh->pjh_nents - (slot + i); goto done; } psc_crc64_init(&chksum); psc_crc64_add(&chksum, pje, offsetof( struct psc_journal_enthdr, pje_chksum)); psc_crc64_add(&chksum, pje->pje_data, pje->pje_len); psc_crc64_fini(&chksum); if (pje->pje_chksum != chksum) { nchksum++; warnx("journal slot %d has a corrupt " "checksum", slot + i); goto done; } ndump++; if (verbose) pjournal_dump_entry(slot + i, pje); if (first) { first = 0; highest_xid = lowest_xid = pje->pje_xid; highest_slot = lowest_slot = slot + i; continue; } if (highest_xid < pje->pje_xid) { highest_xid = pje->pje_xid; highest_slot = slot + i; } if (lowest_xid > pje->pje_xid) { lowest_xid = pje->pje_xid; lowest_slot = slot + i; } } } done: if (close(pj->pj_fd) == -1) printf("failed closing journal %s", fn); psc_free(jbuf, PAF_PAGEALIGN, PJ_PJESZ(pj)); PSCFREE(pj); printf("----------------------------------------------\n" "%8d slot(s) scanned\n" "%8d in use\n" "%8d formatted\n" "%8d bad magic\n" "%8d bad checksum(s)\n" "lowest transaction ID=%#"PRIx64" (slot=%d)\n" "highest transaction ID=%#"PRIx64" (slot=%d)\n", ntotal, ndump, nformat, nmagic, nchksum, lowest_xid, lowest_slot, highest_xid, highest_slot); }