Beispiel #1
0
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);
}
Beispiel #2
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);
}
Beispiel #3
0
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);
}
Beispiel #4
0
/*
 * 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);
}