void slm_fcmh_dtor(struct fidc_membh *f) { struct fcmh_mds_info *fmi; int rc, vfsid; fmi = fcmh_2_fmi(f); if (fcmh_isreg(f)) { psc_assert(psc_dynarray_len(&fmi->fmi_ptrunc_clients) == 0); psc_dynarray_free(&fmi->fmi_ptrunc_clients); } if (fcmh_isreg(f) || fcmh_isdir(f)) { /* XXX Need to worry about other modes here */ if (!fmi->fmi_ctor_rc) { slfid_to_vfsid(fcmh_2_fid(f), &vfsid); rc = mdsio_release(vfsid, &rootcreds, fcmh_2_mfh(f)); psc_assert(rc == 0); } } if (fcmh_isdir(f)) { slfid_to_vfsid(fcmh_2_fid(f), &vfsid); rc = mdsio_release(vfsid, &rootcreds, fcmh_2_dino_mfh(f)); psc_assert(rc == 0); } if (fmi->fmi_inodeh.inoh_extras) PSCFREE(fmi->fmi_inodeh.inoh_extras); }
/* * 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); }
int slm_fcmh_ctor(struct fidc_membh *f, __unusedx int flags) { struct fcmh_mds_info *fmi; struct mio_fh *ino_mfh; struct slm_inoh *ih; mio_fid_t ino_mfid; int rc, vfsid; DEBUG_FCMH(PLL_DIAG, f, "ctor"); rc = slfid_to_vfsid(fcmh_2_fid(f), &vfsid); if (rc) { DEBUG_FCMH(PLL_WARN, f, "invalid file system ID; " "rc=%d", rc); return (rc); } fmi = fcmh_2_fmi(f); memset(fmi, 0, sizeof(*fmi)); rc = mdsio_lookup_slfid(vfsid, fcmh_2_fid(f), &rootcreds, &f->fcmh_sstb, &fcmh_2_mfid(f)); if (rc) { fmi->fmi_ctor_rc = rc; DEBUG_FCMH(PLL_WARN, f, "mdsio_lookup_slfid failed; " "fid="SLPRI_FID" rc=%d", fcmh_2_fid(f), rc); return (rc); } ih = &fmi->fmi_inodeh; ih->inoh_flags = INOH_INO_NOTLOADED; ino_mfid = fcmh_2_mfid(f); ino_mfh = fcmh_2_mfhp(f); if (fcmh_isdir(f)) { mio_fid_t pmfid; char fn[24]; rc = mdsio_opendir(vfsid, fcmh_2_mfid(f), &rootcreds, NULL, &fcmh_2_mfh(f)); if (rc) { DEBUG_FCMH(PLL_WARN, f, "mdsio_opendir failed; " "mio_fid=%"PRIx64" rc=%d", fcmh_2_mfid(f), rc); return (rc); } snprintf(fn, sizeof(fn), "%016"PRIx64".ino", fcmh_2_fid(f)); pmfid = mdsio_getfidlinkdir(fcmh_2_fid(f)); rc = mdsio_lookup(vfsid, pmfid, fn, &fcmh_2_dino_mfid(f), &rootcreds, NULL); if (rc == ENOENT) { struct slm_inox_od inox; rc = mdsio_opencreatef(vfsid, pmfid, &rootcreds, O_CREAT | O_EXCL | O_RDWR, MDSIO_OPENCRF_NOLINK, 0644, fn, &fcmh_2_dino_mfid(f), NULL, &fcmh_2_dino_mfh(f), NULL, NULL, 0); psc_assert(rc == 0); INOH_LOCK(ih); rc = mds_inode_write(vfsid, ih, NULL, NULL); psc_assert(rc == 0); memset(&inox, 0, sizeof(inox)); ih->inoh_extras = &inox; rc = mds_inox_write(vfsid, ih, NULL, NULL); ih->inoh_extras = NULL; INOH_ULOCK(ih); psc_assert(rc == 0); mdsio_release(vfsid, &rootcreds, fcmh_2_dino_mfh(f)); } else if (rc) { fmi->fmi_ctor_rc = rc; DEBUG_FCMH(PLL_WARN, f, "mdsio_lookup failed; rc=%d", rc); return (rc); } ino_mfid = fcmh_2_dino_mfid(f); ino_mfh = fcmh_2_dino_mfhp(f); } if (fcmh_isreg(f)) psc_dynarray_init(&fmi->fmi_ptrunc_clients); if (fcmh_isdir(f) || fcmh_isreg(f)) { /* * We shouldn't need O_LARGEFILE because SLASH2 * metafiles are small. * * I created a file with size of 8070450532247928832 * using dd by seeking to a large offset and writing one * byte. Somehow, the ZFS size becomes 5119601018368. * Without O_LARGEFILE, I got EOVERFLOW (75) here. The * SLASH2 size is correct though. */ rc = mdsio_opencreate(vfsid, ino_mfid, &rootcreds, O_RDWR, 0, NULL, NULL, NULL, &ino_mfh->fh, NULL, NULL, 0); if (rc == 0) { rc = mds_inode_read(&fmi->fmi_inodeh); if (rc) DEBUG_FCMH(PLL_WARN, f, "could not load inode; " "mfid=%"PRIx64" rc=%d", ino_mfid, rc); } else { fmi->fmi_ctor_rc = rc; DEBUG_FCMH(PLL_WARN, f, "mdsio_opencreate failed; " "mfid=%"PRIx64" rc=%d", ino_mfid, rc); } } else DEBUG_FCMH(PLL_DIAG, f, "special file, no zfs obj"); return (rc); }
/* * Handle a request to do replication from a client. May also * reinitialize some parameters of the replication, such as priority, if * the request already exists in the system. */ int mds_repl_addrq(const struct sl_fidgen *fgp, sl_bmapno_t bmapno, sl_bmapno_t *nbmaps, sl_replica_t *iosv, int nios, int sys_prio, int usr_prio) { int tract[NBREPLST], ret_hasvalid[NBREPLST]; int iosidx[SL_MAX_REPLICAS], rc, flags; sl_bmapno_t nbmaps_processed = 0; struct fidc_membh *f = NULL; struct bmap *b; /* Perform sanity checks on request. */ if (nios < 1 || nios > SL_MAX_REPLICAS || *nbmaps == 0) return (-EINVAL); rc = slm_fcmh_get(fgp, &f); if (rc) return (-rc); if (!fcmh_isdir(f) && !fcmh_isreg(f)) PFL_GOTOERR(out, rc = -PFLERR_NOTSUP); /* Lookup replica(s)' indexes in our replica table. */ rc = -mds_repl_iosv_lookup_add(current_vfsid, fcmh_2_inoh(f), iosv, iosidx, nios); if (rc) PFL_GOTOERR(out, rc); /* * If we are modifying a directory, we are done as just the * replica table needs to be updated. */ if (fcmh_isdir(f)) PFL_GOTOERR(out, 0); /* * Setup structure to ensure at least one VALID replica exists. */ brepls_init(ret_hasvalid, 0); ret_hasvalid[BREPLST_VALID] = 1; /* * Setup transitions to enqueue a replication. */ brepls_init(tract, -1); tract[BREPLST_INVALID] = BREPLST_REPL_QUEUED; tract[BREPLST_GARBAGE_SCHED] = BREPLST_REPL_QUEUED; tract[BREPLST_GARBAGE_QUEUED] = BREPLST_REPL_QUEUED; /* Wildcards shouldn't result in errors on zero-length files. */ if (*nbmaps != (sl_bmapno_t)-1) rc = -SLERR_BMAP_INVALID; for (; *nbmaps && bmapno < fcmh_nvalidbmaps(f); bmapno++, --*nbmaps, nbmaps_processed++) { if (nbmaps_processed >= SLM_REPLRQ_NBMAPS_MAX) { rc = -PFLERR_WOULDBLOCK; break; } rc = -bmap_get(f, bmapno, SL_WRITE, &b); if (rc) PFL_GOTOERR(out, rc); /* * If no VALID replicas exist, the bmap must be * uninitialized/all zeroes; skip it. */ if (mds_repl_bmap_walk_all(b, NULL, ret_hasvalid, REPL_WALKF_SCIRCUIT) == 0) { bmap_op_done(b); continue; } /* * We do not follow the standard "retifset" API here * because we need to preserve DIRTY if it gets set * instead of some other state getting returned. */ flags = 0; _mds_repl_bmap_walk(b, tract, NULL, 0, iosidx, nios, slm_repl_addrq_cb, &flags); /* both default to -1 in parse_replrq() */ bmap_2_bmi(b)->bmi_sys_prio = sys_prio; bmap_2_bmi(b)->bmi_usr_prio = usr_prio; if (flags & FLAG_DIRTY) mds_bmap_write_logrepls(b); else if (sys_prio != -1 || usr_prio != -1) slm_repl_upd_write(b, 0); bmap_op_done_type(b, BMAP_OPCNT_LOOKUP); if (flags & FLAG_REPLICA_STATE_INVALID) { /* See pfl_register_errno() */ rc = -SLERR_REPLICA_STATE_INVALID; break; } } out: if (f) fcmh_op_done(f); *nbmaps = nbmaps_processed; return (rc); }