/* * Return the next SLASH2 FID to use. Note that from ZFS point of view, * it is perfectly okay that we use the same SLASH2 FID to refer to * different files/directories. However, doing so can confuse our * clients (think identity theft). So we must make sure that we never * reuse a SLASH2 FID, even after a crash. * * The siteid has already been baked into the initial cursor file. */ int slm_get_next_slashfid(slfid_t *fidp) { uint64_t fid; spinlock(&slm_fid_lock); /* * This should never happen. If it does, we crash to let the * sysadmin know. He could fix this if there is still room in * the cycle bits. We have to let the sysadmin know otherwise * they will not know to bump the cycle bits. */ if (FID_GET_INUM(slm_next_fid) >= FID_MAX_INUM) { psclog_warnx("max FID "SLPRI_FID" reached, manual " "intervention needed (bump the cycle bits)", slm_next_fid); freelock(&slm_fid_lock); return (ENOSPC); } fid = slm_next_fid++; freelock(&slm_fid_lock); psclog_diag("most recently allocated FID: "SLPRI_FID, fid); *fidp = fid; return (0); }
int main(int argc, char *argv[]) { char *p, tmbuf[PFL_CTIME_BUFSIZ], *cursor_file = NULL, c; uint64_t newtxg = 0, newfid = 0, fid, cycle, newcycle; int dump = 0, verbose = 0, fd, rc; struct psc_journal_cursor cursor; progname = argv[0]; while ((c = getopt(argc, argv, "c:df:vx:")) != -1) switch (c) { case 'c': cursor_file = optarg; break; case 'd': dump = 1; break; case 'f': newfid = strtol(optarg, NULL, 0); break; case 'v': verbose = 1; break; case 'x': newtxg = strtol(optarg, NULL, 0); break; default: usage(); } argc -= optind; if (argc || !cursor_file) usage(); fd = open(cursor_file, O_RDWR); if (fd < 0) err(1, "failed to open %s", cursor_file); rc = pread(fd, &cursor, sizeof(struct psc_journal_cursor), 0); if (rc != sizeof(struct psc_journal_cursor)) err(1, "cursor file read"); ctime_r((time_t *)&cursor.pjc_timestamp, tmbuf); p = strchr(tmbuf, '\n'); if (p) *p = '\0'; cycle = FID_GET_CYCLE(cursor.pjc_fid); if (dump || verbose) { printf("Cursor contents of %s:\n" "\tmagic %"PRIx64"\n" "\tversion %"PRIx64"\n" "\ttimestamp %"PRId64" (%s)\n" "\tuuid %s\n" "\tcommit_txg %"PRId64"\n" "\tdistill_xid %"PRId64"\n" "\tfid %#"PRIx64" " "(flag=%"PRIx64", siteid=%"PRIx64", " "cycle=%"PRIx64", inum=%"PRIx64")\n" "\tseqno_lwm %"PRIx64"\n" "\tseqno_hwm %"PRIx64"\n" "\ttail %"PRIx64"\n" "\tupdate_seqno %"PRIx64"\n" "\treclaim_seqno %"PRIx64"\n" "\treplay_xid %"PRIx64"\n\n", cursor_file, cursor.pjc_magic, cursor.pjc_version, cursor.pjc_timestamp, tmbuf, cursor.pjc_uuid, cursor.pjc_commit_txg, cursor.pjc_distill_xid, cursor.pjc_fid, FID_GET_FLAGS(cursor.pjc_fid), FID_GET_SITEID(cursor.pjc_fid), FID_GET_CYCLE(cursor.pjc_fid), FID_GET_INUM(cursor.pjc_fid), cursor.pjc_seqno_lwm, cursor.pjc_seqno_hwm, cursor.pjc_tail, cursor.pjc_update_seqno, cursor.pjc_reclaim_seqno, cursor.pjc_replay_xid); fid = cursor.pjc_fid; fid = fid | FID_MAX_INUM; printf("The max FID for this cycle is %#"PRIx64"\n", fid); if (cycle < ((UINT64_C(1) << SLASH_FID_CYCLE_BITS) - 1)) { fid++; printf("The first FID for the next cycle is %#"PRIx64"\n", fid); } if (dump) exit(0); } if (!newtxg && !newfid) errx(1, "neither fid nor txg was specified"); if (newtxg) cursor.pjc_commit_txg = newtxg; if (newfid) { newcycle = FID_GET_CYCLE(newfid); if (newcycle <= cycle) errx(1, "cycle must be increased when setting a new FID"); cursor.pjc_fid = newfid; } rc = pwrite(fd, &cursor, sizeof(struct psc_journal_cursor), 0); if (rc != sizeof(struct psc_journal_cursor)) err(1, "cursor file write"); if (close(fd) == -1) err(1, "cursor file close"); exit(0); }
/* * Update the high-level app stat(2)-like attribute buffer for a FID * cache member. * @f: FID cache member to update. * @sstb: incoming stat attributes. * @flags: behavioral flags. * Notes: * (1) if SAVELOCAL has been specified, save local field values: * (o) file size * (o) mtime * (2) This function should only be used by a client. */ void slc_fcmh_setattrf(struct fidc_membh *f, struct srt_stat *sstb, int flags) { uidmap_int_stat(sstb); if (flags & FCMH_SETATTRF_HAVELOCK) FCMH_LOCK_ENSURE(f); else FCMH_LOCK(f); if (fcmh_2_gen(f) == FGEN_ANY) fcmh_2_gen(f) = sstb->sst_gen; if ((FID_GET_INUM(fcmh_2_fid(f))) != SLFID_ROOT && fcmh_2_gen(f) > sstb->sst_gen) { OPSTAT_INCR("msl.generation-backwards"); DEBUG_FCMH(PLL_DIAG, f, "attempt to set attr with " "gen %"PRIu64" from old gen %"PRIu64, fcmh_2_gen(f), sstb->sst_gen); goto out; } /* * If we don't have stat attributes, how can we save our local * updates? */ if ((f->fcmh_flags & FCMH_HAVE_ATTRS) == 0) flags |= FCMH_SETATTRF_CLOBBER; /* * Always update for roots because we might have faked them * with readdir at the super root. */ if ((FID_GET_INUM(fcmh_2_fid(f))) == SLFID_ROOT) flags |= FCMH_SETATTRF_CLOBBER; psc_assert(sstb->sst_gen != FGEN_ANY); psc_assert(f->fcmh_fg.fg_fid == sstb->sst_fid); /* * The default behavior is to save st_size and st_mtim since we * might have done I/O that the MDS does not know about. */ if ((flags & FCMH_SETATTRF_CLOBBER) == 0 && fcmh_isreg(f)) { /* * If generation numbers match, take the highest of the * values. Otherwise, disregard local values and * blindly accept whatever the MDS tells us. */ if (fcmh_2_ptruncgen(f) == sstb->sst_ptruncgen && fcmh_2_gen(f) == sstb->sst_gen && fcmh_2_fsz(f) > sstb->sst_size) sstb->sst_size = fcmh_2_fsz(f); if (fcmh_2_utimgen(f) == sstb->sst_utimgen) sstb->sst_mtim = f->fcmh_sstb.sst_mtim; } COPY_SSTB(sstb, &f->fcmh_sstb); f->fcmh_flags |= FCMH_HAVE_ATTRS; f->fcmh_flags &= ~FCMH_GETTING_ATTRS; if (sl_fcmh_ops.sfop_postsetattr) sl_fcmh_ops.sfop_postsetattr(f); DEBUG_FCMH(PLL_DEBUG, f, "attr set"); out: if (!(flags & FCMH_SETATTRF_HAVELOCK)) FCMH_ULOCK(f); }