Пример #1
0
/*
 * Build directory vnodes based on the profile and the global
 * dev instance.
 */
void
prof_filldir(sdev_node_t *ddv)
{
	sdev_node_t *gdir;

	ASSERT(RW_READ_HELD(&ddv->sdev_contents));

	if (!prof_dev_needupdate(ddv)) {
		ASSERT(RW_READ_HELD(&ddv->sdev_contents));
		return;
	}
	/*
	 * Upgrade to writer lock
	 */
	if (rw_tryupgrade(&ddv->sdev_contents) == 0) {
		/*
		 * We need to drop the read lock and re-acquire it as a
		 * write lock. While we do this the condition may change so we
		 * need to re-check condition
		 */
		rw_exit(&ddv->sdev_contents);
		rw_enter(&ddv->sdev_contents, RW_WRITER);
		if (!prof_dev_needupdate(ddv)) {
			/* Downgrade back to the read lock before returning */
			rw_downgrade(&ddv->sdev_contents);
			return;
		}
	}
	/* At this point we should have a write lock */
	ASSERT(RW_WRITE_HELD(&ddv->sdev_contents));

	sdcmn_err10(("devtree_gen (%s): %ld -> %ld\n",
	    ddv->sdev_path, ddv->sdev_devtree_gen, devtree_gen));

	gdir = ddv->sdev_origin;

	if (gdir != NULL)
		sdcmn_err10(("sdev_dir_gen (%s): %ld -> %ld\n",
		    ddv->sdev_path, ddv->sdev_ldir_gen,
		    gdir->sdev_gdir_gen));

	/* update flags and generation number so next filldir is quick */
	if ((ddv->sdev_flags & SDEV_BUILD) == SDEV_BUILD) {
		ddv->sdev_flags &= ~SDEV_BUILD;
	}
	ddv->sdev_devtree_gen = devtree_gen;
	if (gdir != NULL)
		ddv->sdev_ldir_gen = gdir->sdev_gdir_gen;

	prof_make_symlinks(ddv);
	prof_make_maps(ddv);
	prof_make_names(ddv);
	rw_downgrade(&ddv->sdev_contents);
}
Пример #2
0
/*
 * Clean pts sdev_nodes that are no longer valid.
 */
static void
devpts_prunedir(struct sdev_node *ddv)
{
	struct vnode *vp;
	struct sdev_node *dv, *next = NULL;
	int (*vtor)(struct sdev_node *) = NULL;

	ASSERT(ddv->sdev_flags & SDEV_VTOR);

	vtor = (int (*)(struct sdev_node *))sdev_get_vtor(ddv);
	ASSERT(vtor);

	if (rw_tryupgrade(&ddv->sdev_contents) == NULL) {
		rw_exit(&ddv->sdev_contents);
		rw_enter(&ddv->sdev_contents, RW_WRITER);
	}

	for (dv = ddv->sdev_dot; dv; dv = next) {
		next = dv->sdev_next;

		/* skip stale nodes */
		if (dv->sdev_flags & SDEV_STALE)
			continue;

		/* validate and prune only ready nodes */
		if (dv->sdev_state != SDEV_READY)
			continue;

		switch (vtor(dv)) {
		case SDEV_VTOR_VALID:
		case SDEV_VTOR_SKIP:
			continue;
		case SDEV_VTOR_INVALID:
			sdcmn_err7(("prunedir: destroy invalid "
			    "node: %s(%p)\n", dv->sdev_name, (void *)dv));
			break;
		}
		vp = SDEVTOV(dv);
		if (vp->v_count > 0)
			continue;
		SDEV_HOLD(dv);
		/* remove the cache node */
		(void) sdev_cache_update(ddv, &dv, dv->sdev_name,
		    SDEV_CACHE_DELETE);
	}
	rw_downgrade(&ddv->sdev_contents);
}
Пример #3
0
static int
splat_rwlock_test5(struct file *file, void *arg)
{
	rw_priv_t *rwp;
	int rc = -EINVAL;

	rwp = (rw_priv_t *)kmalloc(sizeof(*rwp), GFP_KERNEL);
	if (rwp == NULL)
		return -ENOMEM;

	splat_init_rw_priv(rwp, file);

	rw_enter(&rwp->rw_rwlock, RW_WRITER);
	if (!RW_WRITE_HELD(&rwp->rw_rwlock)) {
		splat_vprint(file, SPLAT_RWLOCK_TEST5_NAME,
			     "rwlock should be write lock: %d\n",
			     RW_WRITE_HELD(&rwp->rw_rwlock));
		goto out;
	}

	rw_downgrade(&rwp->rw_rwlock);
	if (!RW_READ_HELD(&rwp->rw_rwlock)) {
		splat_vprint(file, SPLAT_RWLOCK_TEST5_NAME,
			     "rwlock should be read lock: %d\n",
			     RW_READ_HELD(&rwp->rw_rwlock));
		goto out;
	}

	rc = 0;
	splat_vprint(file, SPLAT_RWLOCK_TEST5_NAME, "%s",
		     "rwlock properly downgraded\n");
out:
	rw_exit(&rwp->rw_rwlock);
	rw_destroy(&rwp->rw_rwlock);
	kfree(rwp);

	return rc;
}
Пример #4
0
void
rumpuser_rw_downgrade(struct rumpuser_rw *rw)
{

	rw_downgrade(rw);
}
Пример #5
0
int
sam_refresh_shared_reader_ino(
	sam_node_t *ip,			/* Pointer to the inode */
	boolean_t writelock,		/* Inode WRITER lock held, */
					/*   otherwise READER lock held. */
	cred_t *credp)			/* credentials. */
{
	sam_id_t id;
	struct sam_perm_inode *permip;
	buf_t *bp;
	int refresh = 0;
	int error;

	if ((ip->updtime + ip->mp->mt.fi_invalid) > SAM_SECOND()) {
		return (0);
	}

	if (!writelock) {
		/*
		 * Acquire inode lock before buffer lock. Recheck the update
		 * time.
		 */
		if (!rw_tryupgrade(&ip->inode_rwl)) {
			RW_UNLOCK_OS(&ip->inode_rwl, RW_READER);
			RW_LOCK_OS(&ip->inode_rwl, RW_WRITER);
			if ((ip->updtime + ip->mp->mt.fi_invalid) >
			    SAM_SECOND()) {
				error = 0;
				goto out;
			}
		}
	}
	id = ip->di.id;
	if ((error = sam_read_ino(ip->mp, id.ino, &bp, &permip))) {
		goto out;
	}
	if ((permip->di.mode != 0) && (permip->di.id.ino == ip->di.id.ino) &&
	    (permip->di.id.gen == ip->di.id.gen)) {
		if ((permip->di.modify_time.tv_sec !=
		    ip->di.modify_time.tv_sec) ||
		    (permip->di.modify_time.tv_nsec !=
		    ip->di.modify_time.tv_nsec)||
		    (permip->di.change_time.tv_sec !=
		    ip->di.change_time.tv_sec) ||
		    (permip->di.change_time.tv_nsec !=
		    ip->di.change_time.tv_nsec)||
		    (permip->di.residence_time != ip->di.residence_time) ||
		    (permip->di.rm.size != ip->di.rm.size) ||
		    (permip->di.mode != ip->di.mode)) {
			refresh = 1;
		} else {
			ip->di.uid = permip->di.uid;
			ip->di.gid = permip->di.gid;
		}
	} else {
		refresh = 1;
		error = ENOENT;		/* This inode has been removed */
	}
	if (refresh) {
		vnode_t *vp = SAM_ITOV(ip);

		/*
		 * If a refresh is needed on a directory inode,
		 * invalidate associated dnlc entries.
		 */
		if (S_ISDIR(ip->di.mode)) {
			sam_invalidate_dnlc(vp);
		}

		/*
		 * Move shared_writer's inode copy into inode. Set size
		 * and invalidate pages. Set shared_reader update time.
		 */
		ip->di = permip->di; /* Move disk ino to incore ino */
		ip->di2 = permip->di2;
		brelse(bp);
		vp->v_type = IFTOVT(S_ISREQ(ip->di.mode) ?
		    S_IFREG : ip->di.mode);
		sam_set_size(ip);
		(void) VOP_PUTPAGE_OS(vp, 0, 0, B_INVAL, credp, NULL);
		if (ip->di.status.b.acl) {
			(void) sam_acl_inactive(ip);
			error = sam_get_acl(ip, &ip->aclp);
		}
		ip->updtime = SAM_SECOND();
	} else {
		ip->updtime = SAM_SECOND();
		brelse(bp);
	}

out:
	if (!writelock) {
		rw_downgrade(&ip->inode_rwl);
	}
	return (error);
}
Пример #6
0
int
zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx,
    krw_t lti, int fatreader, zap_t **zapp)
{
	zap_t *zap;
	dmu_buf_t *db;
	krw_t lt;
	int err;

	*zapp = NULL;

	err = dmu_buf_hold(os, obj, 0, NULL, &db);
	if (err)
		return (err);

#ifdef ZFS_DEBUG
	{
		dmu_object_info_t doi;
		dmu_object_info_from_db(db, &doi);
		ASSERT(dmu_ot[doi.doi_type].ot_byteswap == zap_byteswap);
	}
#endif

	zap = dmu_buf_get_user(db);
	if (zap == NULL)
		zap = mzap_open(os, obj, db);

	/*
	 * We're checking zap_ismicro without the lock held, in order to
	 * tell what type of lock we want.  Once we have some sort of
	 * lock, see if it really is the right type.  In practice this
	 * can only be different if it was upgraded from micro to fat,
	 * and micro wanted WRITER but fat only needs READER.
	 */
	lt = (!zap->zap_ismicro && fatreader) ? RW_READER : lti;
	rw_enter(&zap->zap_rwlock, lt);
	if (lt != ((!zap->zap_ismicro && fatreader) ? RW_READER : lti)) {
		/* it was upgraded, now we only need reader */
		ASSERT(lt == RW_WRITER);
		ASSERT(RW_READER ==
		    (!zap->zap_ismicro && fatreader) ? RW_READER : lti);
		rw_downgrade(&zap->zap_rwlock);
		lt = RW_READER;
	}

	zap->zap_objset = os;

	if (lt == RW_WRITER)
		dmu_buf_will_dirty(db, tx);

	ASSERT3P(zap->zap_dbuf, ==, db);

	ASSERT(!zap->zap_ismicro ||
	    zap->zap_m.zap_num_entries <= zap->zap_m.zap_num_chunks);
	if (zap->zap_ismicro && tx &&
	    zap->zap_m.zap_num_entries == zap->zap_m.zap_num_chunks) {
		uint64_t newsz = db->db_size + SPA_MINBLOCKSIZE;
		if (newsz > MZAP_MAX_BLKSZ) {
			dprintf("upgrading obj %llu: num_entries=%u\n",
			    obj, zap->zap_m.zap_num_entries);
			mzap_upgrade(zap, tx);
			*zapp = zap;
			return (0);
		}
		err = dmu_object_set_blocksize(os, obj, newsz, 0, tx);
		ASSERT3U(err, ==, 0);
		zap->zap_m.zap_num_chunks =
		    db->db_size / MZAP_ENT_LEN - 1;
	}
Пример #7
0
static void
devvt_cleandir(struct vnode *dvp, struct cred *cred)
{
	struct sdev_node *sdvp = VTOSDEV(dvp);
	struct sdev_node *dv, *next = NULL;
	int min, cnt;
	char found = 0;

	mutex_enter(&vc_lock);
	cnt = VC_INSTANCES_COUNT;
	mutex_exit(&vc_lock);

/* We have to fool warlock this way, otherwise it will complain */
#ifndef	__lock_lint
	if (rw_tryupgrade(&sdvp->sdev_contents) == NULL) {
		rw_exit(&sdvp->sdev_contents);
		rw_enter(&sdvp->sdev_contents, RW_WRITER);
	}
#else
	rw_enter(&sdvp->sdev_contents, RW_WRITER);
#endif

	/* 1.  prune invalid nodes and rebuild stale symlinks */
	devvt_prunedir(sdvp);

	/* 2. create missing nodes */
	for (min = 0; min < cnt; min++) {
		char nm[16];

		if (vt_minor_valid(min) == B_FALSE)
			continue;

		(void) snprintf(nm, sizeof (nm), "%d", min);
		found = 0;
		for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) {
			next = SDEV_NEXT_ENTRY(sdvp, dv);

			/* validate only ready nodes */
			if (dv->sdev_state != SDEV_READY)
				continue;
			if (strcmp(nm, dv->sdev_name) == 0) {
				found = 1;
				break;
			}
		}
		if (!found) {
			devvt_create_snode(sdvp, nm, cred, SDEV_VATTR);
		}
	}

	/* 3. create active link node and console user link node */
	found = 0;
	for (dv = SDEV_FIRST_ENTRY(sdvp); dv; dv = next) {
		next = SDEV_NEXT_ENTRY(sdvp, dv);

		/* validate only ready nodes */
		if (dv->sdev_state != SDEV_READY)
			continue;
		if ((strcmp(dv->sdev_name, DEVVT_ACTIVE_NAME) == NULL))
			found |= 0x01;
		if ((strcmp(dv->sdev_name, DEVVT_CONSUSER_NAME) == NULL))
			found |= 0x02;

		if ((found & 0x01) && (found & 0x02))
			break;
	}
	if (!(found & 0x01))
		devvt_create_snode(sdvp, DEVVT_ACTIVE_NAME, cred, SDEV_VLINK);
	if (!(found & 0x02))
		devvt_create_snode(sdvp, DEVVT_CONSUSER_NAME, cred, SDEV_VLINK);

#ifndef	__lock_lint
	rw_downgrade(&sdvp->sdev_contents);
#else
	rw_exit(&sdvp->sdev_contents);
#endif
}
Пример #8
0
/*
 * If DV_BUILD is set, we call into nexus driver to do a BUS_CONFIG_ALL.
 * Otherwise, simply return cached dv_node's. Hotplug code always call
 * devfs_clean() to invalid the dv_node cache.
 */
static int
devfs_readdir(struct vnode *dvp, struct uio *uiop, struct cred *cred, int *eofp)
{
	struct dv_node *ddv, *dv;
	struct dirent64 *de, *bufp;
	offset_t diroff;
	offset_t	soff;
	size_t reclen, movesz;
	int error;
	struct vattr va;
	size_t bufsz;

	ddv = VTODV(dvp);
	dcmn_err2(("devfs_readdir %s: offset %lld len %ld\n",
	    ddv->dv_name, uiop->uio_loffset, uiop->uio_iov->iov_len));
	ASSERT(ddv->dv_attr || ddv->dv_attrvp);
	ASSERT(RW_READ_HELD(&ddv->dv_contents));

	if (uiop->uio_loffset >= MAXOFF_T) {
		if (eofp)
			*eofp = 1;
		return (0);
	}

	if (uiop->uio_iovcnt != 1)
		return (EINVAL);

	if (dvp->v_type != VDIR)
		return (ENOTDIR);

	/* Load the initial contents */
	if (ddv->dv_flags & DV_BUILD) {
		if (!rw_tryupgrade(&ddv->dv_contents)) {
			rw_exit(&ddv->dv_contents);
			rw_enter(&ddv->dv_contents, RW_WRITER);
		}

		/* recheck and fill */
		if (ddv->dv_flags & DV_BUILD)
			dv_filldir(ddv);

		rw_downgrade(&ddv->dv_contents);
	}

	soff = uiop->uio_offset;
	bufsz = uiop->uio_iov->iov_len;
	de = bufp = kmem_alloc(bufsz, KM_SLEEP);
	movesz = 0;
	dv = (struct dv_node *)-1;

	/*
	 * Move as many entries into the uio structure as it will take.
	 * Special case "." and "..".
	 */
	diroff = 0;
	if (soff == 0) {				/* . */
		reclen = DIRENT64_RECLEN(strlen("."));
		if ((movesz + reclen) > bufsz)
			goto full;
		de->d_ino = (ino64_t)ddv->dv_ino;
		de->d_off = (off64_t)diroff + 1;
		de->d_reclen = (ushort_t)reclen;

		/* use strncpy(9f) to zero out uninitialized bytes */

		(void) strncpy(de->d_name, ".", DIRENT64_NAMELEN(reclen));
		movesz += reclen;
		de = (dirent64_t *)((char *)de + reclen);
		dcmn_err3(("devfs_readdir: A: diroff %lld, soff %lld: '%s' "
		    "reclen %lu\n", diroff, soff, ".", reclen));
	}

	diroff++;
	if (soff <= 1) {				/* .. */
		reclen = DIRENT64_RECLEN(strlen(".."));
		if ((movesz + reclen) > bufsz)
			goto full;
		de->d_ino = (ino64_t)ddv->dv_dotdot->dv_ino;
		de->d_off = (off64_t)diroff + 1;
		de->d_reclen = (ushort_t)reclen;

		/* use strncpy(9f) to zero out uninitialized bytes */

		(void) strncpy(de->d_name, "..", DIRENT64_NAMELEN(reclen));
		movesz += reclen;
		de = (dirent64_t *)((char *)de + reclen);
		dcmn_err3(("devfs_readdir: B: diroff %lld, soff %lld: '%s' "
		    "reclen %lu\n", diroff, soff, "..", reclen));
	}

	diroff++;
	for (dv = ddv->dv_dot; dv; dv = dv->dv_next, diroff++) {
		/*
		 * although DDM_INTERNAL_PATH minor nodes are skipped for
		 * readdirs outside the kernel, they still occupy directory
		 * offsets
		 */
		if (diroff < soff ||
		    ((dv->dv_flags & DV_INTERNAL) && (cred != kcred)))
			continue;

		reclen = DIRENT64_RECLEN(strlen(dv->dv_name));
		if ((movesz + reclen) > bufsz) {
			dcmn_err3(("devfs_readdir: C: diroff "
			    "%lld, soff %lld: '%s' reclen %lu\n",
			    diroff, soff, dv->dv_name, reclen));
			goto full;
		}
		de->d_ino = (ino64_t)dv->dv_ino;
		de->d_off = (off64_t)diroff + 1;
		de->d_reclen = (ushort_t)reclen;

		/* use strncpy(9f) to zero out uninitialized bytes */

		ASSERT(strlen(dv->dv_name) + 1 <=
		    DIRENT64_NAMELEN(reclen));
		(void) strncpy(de->d_name, dv->dv_name,
		    DIRENT64_NAMELEN(reclen));

		movesz += reclen;
		de = (dirent64_t *)((char *)de + reclen);
		dcmn_err4(("devfs_readdir: D: diroff "
		    "%lld, soff %lld: '%s' reclen %lu\n", diroff, soff,
		    dv->dv_name, reclen));
	}

	/* the buffer is full, or we exhausted everything */
full:	dcmn_err3(("devfs_readdir: moving %lu bytes: "
	    "diroff %lld, soff %lld, dv %p\n",
	    movesz, diroff, soff, (void *)dv));

	if ((movesz == 0) && dv)
		error = EINVAL;		/* cannot be represented */
	else {
		error = uiomove(bufp, movesz, UIO_READ, uiop);
		if (error == 0) {
			if (eofp)
				*eofp = dv ? 0 : 1;
			uiop->uio_offset = diroff;
		}

		va.va_mask = AT_ATIME;
		gethrestime(&va.va_atime);
		rw_exit(&ddv->dv_contents);
		(void) devfs_setattr(dvp, &va, 0, cred, NULL);
		rw_enter(&ddv->dv_contents, RW_READER);
	}

	kmem_free(bufp, bufsz);
	return (error);
}