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)); }
/* * 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); }
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); }
/* * 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)); }
/* * 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)); }
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); }
/* * 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); }
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); } }