示例#1
0
void
zil_free(zilog_t *zilog)
{
	lwb_t *lwb;

	zilog->zl_stop_sync = 1;

	while ((lwb = list_head(&zilog->zl_lwb_list)) != NULL) {
		list_remove(&zilog->zl_lwb_list, lwb);
		if (lwb->lwb_buf != NULL)
			zio_buf_free(lwb->lwb_buf, lwb->lwb_sz);
		kmem_cache_free(zil_lwb_cache, lwb);
	}
	list_destroy(&zilog->zl_lwb_list);

	avl_destroy(&zilog->zl_vdev_tree);
	mutex_destroy(&zilog->zl_vdev_lock);

	ASSERT(list_head(&zilog->zl_itx_list) == NULL);
	list_destroy(&zilog->zl_itx_list);
	mutex_destroy(&zilog->zl_lock);

	cv_destroy(&zilog->zl_cv_writer);
	cv_destroy(&zilog->zl_cv_suspend);

	kmem_free(zilog, sizeof (zilog_t));
}
示例#2
0
文件: zil.c 项目: harshada/zfs
/*
 * In one tx, free all log blocks and clear the log header.
 * If keep_first is set, then we're replaying a log with no content.
 * We want to keep the first block, however, so that the first
 * synchronous transaction doesn't require a txg_wait_synced()
 * in zil_create().  We don't need to txg_wait_synced() here either
 * when keep_first is set, because both zil_create() and zil_destroy()
 * will wait for any in-progress destroys to complete.
 */
void
zil_destroy(zilog_t *zilog, boolean_t keep_first)
{
	const zil_header_t *zh = zilog->zl_header;
	lwb_t *lwb;
	dmu_tx_t *tx;
	uint64_t txg;

	/*
	 * Wait for any previous destroy to complete.
	 */
	txg_wait_synced(zilog->zl_dmu_pool, zilog->zl_destroy_txg);

	if (BP_IS_HOLE(&zh->zh_log))
		return;

	tx = dmu_tx_create(zilog->zl_os);
	(void) dmu_tx_assign(tx, TXG_WAIT);
	dsl_dataset_dirty(dmu_objset_ds(zilog->zl_os), tx);
	txg = dmu_tx_get_txg(tx);

	mutex_enter(&zilog->zl_lock);

	/*
	 * It is possible for the ZIL to get the previously mounted zilog
	 * structure of the same dataset if quickly remounted and the dbuf
	 * eviction has not completed. In this case we can see a non
	 * empty lwb list and keep_first will be set. We fix this by
	 * clearing the keep_first. This will be slower but it's very rare.
	 */
	if (!list_is_empty(&zilog->zl_lwb_list) && keep_first)
		keep_first = B_FALSE;

	ASSERT3U(zilog->zl_destroy_txg, <, txg);
	zilog->zl_destroy_txg = txg;
	zilog->zl_keep_first = keep_first;

	if (!list_is_empty(&zilog->zl_lwb_list)) {
		ASSERT(zh->zh_claim_txg == 0);
		ASSERT(!keep_first);
		while ((lwb = list_head(&zilog->zl_lwb_list)) != NULL) {
			list_remove(&zilog->zl_lwb_list, lwb);
			if (lwb->lwb_buf != NULL)
				zio_buf_free(lwb->lwb_buf, lwb->lwb_sz);
			zio_free_blk(zilog->zl_spa, &lwb->lwb_blk, txg);
			kmem_cache_free(zil_lwb_cache, lwb);
		}
	} else {
		if (!keep_first) {
			(void) zil_parse(zilog, zil_free_log_block,
			    zil_free_log_record, tx, zh->zh_claim_txg);
		}
	}
	mutex_exit(&zilog->zl_lock);

	dmu_tx_commit(tx);
}
示例#3
0
static void
vdev_queue_agg_io_done(zio_t *aio)
{
	zio_t *pio;

	while ((pio = zio_walk_parents(aio)) != NULL)
		if (aio->io_type == ZIO_TYPE_READ)
			bcopy((char *)aio->io_data + (pio->io_offset -
			    aio->io_offset), pio->io_data, pio->io_size);

	zio_buf_free(aio->io_data, aio->io_size);
}
示例#4
0
/*
 * Evict the specified entry from the cache.
 */
static void
vdev_cache_evict(vdev_cache_t *vc, vdev_cache_entry_t *ve)
{
	ASSERT(MUTEX_HELD(&vc->vc_lock));
	ASSERT(ve->ve_fill_io == NULL);
	ASSERT(ve->ve_data != NULL);

	avl_remove(&vc->vc_lastused_tree, ve);
	avl_remove(&vc->vc_offset_tree, ve);
	zio_buf_free(ve->ve_data, VCBS);
	kmem_free(ve, sizeof (vdev_cache_entry_t));
}
示例#5
0
/*
 * Evict the specified entry from the cache.
 */
static void
vdev_cache_evict(vdev_cache_t *vc, vdev_cache_entry_t *ve)
{
	ASSERT(MUTEX_HELD(&vc->vc_lock));
	ASSERT(ve->ve_fill_io == NULL);
	ASSERT(ve->ve_data != NULL);

	dprintf("evicting %p, off %llx, LRU %llu, age %lu, hits %u, stale %u\n",
	    vc, ve->ve_offset, ve->ve_lastused, lbolt - ve->ve_lastused,
	    ve->ve_hits, ve->ve_missed_update);

	avl_remove(&vc->vc_lastused_tree, ve);
	avl_remove(&vc->vc_offset_tree, ve);
	zio_buf_free(ve->ve_data, VCBS);
	kmem_free(ve, sizeof (vdev_cache_entry_t));
}
示例#6
0
文件: zfs_sa.c 项目: avg-I/zfs
int
zfs_sa_set_xattr(znode_t *zp)
{
    zfs_sb_t *zsb = ZTOZSB(zp);
    dmu_tx_t *tx;
    char *obj;
    size_t size;
    int error;

    ASSERT(RW_WRITE_HELD(&zp->z_xattr_lock));
    ASSERT(zp->z_xattr_cached);
    ASSERT(zp->z_is_sa);

    error = nvlist_size(zp->z_xattr_cached, &size, NV_ENCODE_XDR);
    if (error)
        goto out;

    obj = zio_buf_alloc(size);

    error = nvlist_pack(zp->z_xattr_cached, &obj, &size,
                        NV_ENCODE_XDR, KM_SLEEP);
    if (error)
        goto out_free;

    tx = dmu_tx_create(zsb->z_os);
    dmu_tx_hold_sa_create(tx, size);
    dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_TRUE);

    error = dmu_tx_assign(tx, TXG_WAIT);
    if (error) {
        dmu_tx_abort(tx);
    } else {
        error = sa_update(zp->z_sa_hdl, SA_ZPL_DXATTR(zsb),
                          obj, size, tx);
        if (error)
            dmu_tx_abort(tx);
        else
            dmu_tx_commit(tx);
    }
out_free:
    zio_buf_free(obj, size);
out:
    return (error);
}
static void
vdev_queue_agg_io_done(zio_t *aio)
{
	zio_t *dio;
	uint64_t offset = 0;

	while ((dio = aio->io_delegate_list) != NULL) {
		if (aio->io_type == ZIO_TYPE_READ)
			bcopy((char *)aio->io_data + offset, dio->io_data,
			    dio->io_size);
		offset += dio->io_size;
		aio->io_delegate_list = dio->io_delegate_next;
		dio->io_delegate_next = NULL;
		dio->io_error = aio->io_error;
		zio_execute(dio);
	}
	ASSERT3U(offset, ==, aio->io_size);

	zio_buf_free(aio->io_data, aio->io_size);
}
示例#8
0
文件: zil.c 项目: harshada/zfs
/*
 * Function called when a log block write completes
 */
static void
zil_lwb_write_done(zio_t *zio)
{
	lwb_t *lwb = zio->io_private;
	zilog_t *zilog = lwb->lwb_zilog;

	ASSERT(BP_GET_COMPRESS(zio->io_bp) == ZIO_COMPRESS_OFF);
	ASSERT(BP_GET_CHECKSUM(zio->io_bp) == ZIO_CHECKSUM_ZILOG);
	ASSERT(BP_GET_TYPE(zio->io_bp) == DMU_OT_INTENT_LOG);
	ASSERT(BP_GET_LEVEL(zio->io_bp) == 0);
	ASSERT(BP_GET_BYTEORDER(zio->io_bp) == ZFS_HOST_BYTEORDER);
	ASSERT(!BP_IS_GANG(zio->io_bp));
	ASSERT(!BP_IS_HOLE(zio->io_bp));
	ASSERT(zio->io_bp->blk_fill == 0);

	/*
	 * Ensure the lwb buffer pointer is cleared before releasing
	 * the txg. If we have had an allocation failure and
	 * the txg is waiting to sync then we want want zil_sync()
	 * to remove the lwb so that it's not picked up as the next new
	 * one in zil_commit_writer(). zil_sync() will only remove
	 * the lwb if lwb_buf is null.
	 */
	zio_buf_free(lwb->lwb_buf, lwb->lwb_sz);
	mutex_enter(&zilog->zl_lock);
	lwb->lwb_buf = NULL;
	if (zio->io_error)
		zilog->zl_log_error = B_TRUE;

	/*
	 * Now that we've written this log block, we have a stable pointer
	 * to the next block in the chain, so it's OK to let the txg in
	 * which we allocated the next block sync. We still have the
	 * zl_lock to ensure zil_sync doesn't kmem free the lwb.
	 */
	txg_rele_to_sync(&lwb->lwb_txgh);
	mutex_exit(&zilog->zl_lock);
}
int
zio_compress_data(int cpfunc, void *src, uint64_t srcsize, void **destp,
    uint64_t *destsizep, uint64_t *destbufsizep)
{
	uint64_t *word, *word_end;
	uint64_t ciosize, gapsize, destbufsize;
	zio_compress_info_t *ci = &zio_compress_table[cpfunc];
	char *dest;
	uint_t allzero;

	ASSERT((uint_t)cpfunc < ZIO_COMPRESS_FUNCTIONS);
	ASSERT((uint_t)cpfunc == ZIO_COMPRESS_EMPTY || ci->ci_compress != NULL);

	/*
	 * If the data is all zeroes, we don't even need to allocate
	 * a block for it.  We indicate this by setting *destsizep = 0.
	 */
	allzero = 1;
	word = src;
	word_end = (uint64_t *)(uintptr_t)((uintptr_t)word + srcsize);
	while (word < word_end) {
		if (*word++ != 0) {
			allzero = 0;
			break;
		}
	}
	if (allzero) {
		*destp = NULL;
		*destsizep = 0;
		*destbufsizep = 0;
		return (1);
	}

	if (cpfunc == ZIO_COMPRESS_EMPTY)
		return (0);

	/* Compress at least 12.5% */
	destbufsize = P2ALIGN(srcsize - (srcsize >> 3), SPA_MINBLOCKSIZE);
	if (destbufsize == 0)
		return (0);
	dest = zio_buf_alloc(destbufsize);

	ciosize = ci->ci_compress(src, dest, (size_t)srcsize,
	    (size_t)destbufsize, ci->ci_level);
	if (ciosize > destbufsize) {
		zio_buf_free(dest, destbufsize);
		return (0);
	}

	/* Cool.  We compressed at least as much as we were hoping to. */

	/* For security, make sure we don't write random heap crap to disk */
	gapsize = P2ROUNDUP(ciosize, SPA_MINBLOCKSIZE) - ciosize;
	if (gapsize != 0) {
		bzero(dest + ciosize, gapsize);
		ciosize += gapsize;
	}

	ASSERT3U(ciosize, <=, destbufsize);
	ASSERT(P2PHASE(ciosize, SPA_MINBLOCKSIZE) == 0);
	*destp = dest;
	*destsizep = ciosize;
	*destbufsizep = destbufsize;

	return (1);
}
示例#10
0
文件: dmu_objset.c 项目: harshada/zfs
void
dmu_objset_do_userquota_callbacks(objset_impl_t *os, dmu_tx_t *tx)
{
	dnode_t *dn;
	list_t *list = &os->os_synced_dnodes;
	ASSERTV(static const char zerobuf[DN_MAX_BONUSLEN] = {0});

	ASSERT(list_head(list) == NULL || dmu_objset_userused_enabled(os));

	while ((dn = list_head(list))) {
		dmu_object_type_t bonustype;

		ASSERT(!DMU_OBJECT_IS_SPECIAL(dn->dn_object));
		ASSERT(dn->dn_oldphys);
		ASSERT(dn->dn_phys->dn_type == DMU_OT_NONE ||
		    dn->dn_phys->dn_flags &
		    DNODE_FLAG_USERUSED_ACCOUNTED);

		/* Allocate the user/groupused objects if necessary. */
		if (os->os_userused_dnode->dn_type == DMU_OT_NONE) {
			VERIFY(0 == zap_create_claim(&os->os,
			    DMU_USERUSED_OBJECT,
			    DMU_OT_USERGROUP_USED, DMU_OT_NONE, 0, tx));
			VERIFY(0 == zap_create_claim(&os->os,
			    DMU_GROUPUSED_OBJECT,
			    DMU_OT_USERGROUP_USED, DMU_OT_NONE, 0, tx));
		}

		/*
		 * If the object was not previously
		 * accounted, pretend that it was free.
		 */
		if (!(dn->dn_oldphys->dn_flags &
		    DNODE_FLAG_USERUSED_ACCOUNTED)) {
			bzero(dn->dn_oldphys, sizeof (dnode_phys_t));
		}

		/*
		 * If the object was freed, use the previous bonustype.
		 */
		bonustype = dn->dn_phys->dn_bonustype ?
		    dn->dn_phys->dn_bonustype : dn->dn_oldphys->dn_bonustype;
		ASSERT(dn->dn_phys->dn_type != 0 ||
		    (bcmp(DN_BONUS(dn->dn_phys), zerobuf,
		    DN_MAX_BONUSLEN) == 0 &&
		    DN_USED_BYTES(dn->dn_phys) == 0));
		ASSERT(dn->dn_oldphys->dn_type != 0 ||
		    (bcmp(DN_BONUS(dn->dn_oldphys), zerobuf,
		    DN_MAX_BONUSLEN) == 0 &&
		    DN_USED_BYTES(dn->dn_oldphys) == 0));
		used_cbs[os->os_phys->os_type](&os->os, bonustype,
		    DN_BONUS(dn->dn_oldphys), DN_BONUS(dn->dn_phys),
		    DN_USED_BYTES(dn->dn_oldphys),
		    DN_USED_BYTES(dn->dn_phys), tx);

		/*
		 * The mutex is needed here for interlock with dnode_allocate.
		 */
		mutex_enter(&dn->dn_mtx);
		zio_buf_free(dn->dn_oldphys, sizeof (dnode_phys_t));
		dn->dn_oldphys = NULL;
		mutex_exit(&dn->dn_mtx);

		list_remove(list, dn);
		dnode_rele(dn, list);
	}
}