static int zvol_discard(struct bio *bio) { zvol_state_t *zv = bio->bi_bdev->bd_disk->private_data; uint64_t start = BIO_BI_SECTOR(bio) << 9; uint64_t size = BIO_BI_SIZE(bio); uint64_t end = start + size; int error; rl_t *rl; dmu_tx_t *tx; ASSERT(zv && zv->zv_open_count > 0); if (end > zv->zv_volsize) return (SET_ERROR(EIO)); /* * Align the request to volume block boundaries when REQ_SECURE is * available, but not requested. If we don't, then this will force * dnode_free_range() to zero out the unaligned parts, which is slow * (read-modify-write) and useless since we are not freeing any space * by doing so. Kernels that do not support REQ_SECURE (2.6.32 through * 2.6.35) will not receive this optimization. */ #ifdef REQ_SECURE if (!(bio->bi_rw & REQ_SECURE)) { start = P2ROUNDUP(start, zv->zv_volblocksize); end = P2ALIGN(end, zv->zv_volblocksize); size = end - start; } #endif if (start >= end) return (0); rl = zfs_range_lock(&zv->zv_znode, start, size, RL_WRITER); tx = dmu_tx_create(zv->zv_objset); dmu_tx_mark_netfree(tx); error = dmu_tx_assign(tx, TXG_WAIT); if (error != 0) { dmu_tx_abort(tx); } else { zvol_log_truncate(zv, tx, start, size, B_TRUE); dmu_tx_commit(tx); error = dmu_free_long_range(zv->zv_objset, ZVOL_OBJ, start, size); } zfs_range_unlock(rl); return (error); }
static int zvol_discard(struct bio *bio) { zvol_state_t *zv = bio->bi_bdev->bd_disk->private_data; uint64_t start = BIO_BI_SECTOR(bio) << 9; uint64_t size = BIO_BI_SIZE(bio); uint64_t end = start + size; int error; rl_t *rl; dmu_tx_t *tx; ASSERT(zv && zv->zv_open_count > 0); if (end > zv->zv_volsize) return (SET_ERROR(EIO)); /* * Align the request to volume block boundaries when a secure erase is * not required. This will prevent dnode_free_range() from zeroing out * the unaligned parts which is slow (read-modify-write) and useless * since we are not freeing any space by doing so. */ if (!bio_is_secure_erase(bio)) { start = P2ROUNDUP(start, zv->zv_volblocksize); end = P2ALIGN(end, zv->zv_volblocksize); size = end - start; } if (start >= end) return (0); rl = zfs_range_lock(&zv->zv_range_lock, start, size, RL_WRITER); tx = dmu_tx_create(zv->zv_objset); dmu_tx_mark_netfree(tx); error = dmu_tx_assign(tx, TXG_WAIT); if (error != 0) { dmu_tx_abort(tx); } else { zvol_log_truncate(zv, tx, start, size, B_TRUE); dmu_tx_commit(tx); error = dmu_free_long_range(zv->zv_objset, ZVOL_OBJ, start, size); } zfs_range_unlock(rl); return (error); }