diff --git a/include/sys/dmu.h b/include/sys/dmu.h index 6459047e8f35..2abc4357fc7e 100644 --- a/include/sys/dmu.h +++ b/include/sys/dmu.h @@ -476,6 +476,8 @@ int dmu_spill_hold_existing(dmu_buf_t *bonus, void *tag, dmu_buf_t **dbp); */ int dmu_buf_hold(objset_t *os, uint64_t object, uint64_t offset, void *tag, dmu_buf_t **, int flags); +int dmu_buf_hold_by_dbuf(dmu_buf_t *zdb, uint64_t offset, + void *tag, dmu_buf_t **, int flags); int dmu_buf_hold_by_dnode(dnode_t *dn, uint64_t offset, void *tag, dmu_buf_t **dbp, int flags); @@ -741,6 +743,8 @@ int dmu_read(objset_t *os, uint64_t object, uint64_t offset, uint64_t size, void *buf, uint32_t flags); int dmu_read_by_dnode(dnode_t *dn, uint64_t offset, uint64_t size, void *buf, uint32_t flags); +int dmu_read_by_dbuf(dmu_buf_t *zdb, uint64_t offset, uint64_t size, void *buf, + uint32_t flags); void dmu_write(objset_t *os, uint64_t object, uint64_t offset, uint64_t size, const void *buf, dmu_tx_t *tx); void dmu_write_by_dnode(dnode_t *dn, uint64_t offset, uint64_t size, diff --git a/module/zfs/dmu.c b/module/zfs/dmu.c index 4929ef9ab737..f96d31d5176c 100644 --- a/module/zfs/dmu.c +++ b/module/zfs/dmu.c @@ -212,6 +212,23 @@ dmu_buf_hold_by_dnode(dnode_t *dn, uint64_t offset, return (err); } +int +dmu_buf_hold_by_dbuf(dmu_buf_t *zdb, uint64_t offset, + void *tag, dmu_buf_t **dbp, int flags) +{ + dmu_buf_impl_t *db = (dmu_buf_impl_t *)zdb; + dnode_t *dn; + int err; + + + DB_DNODE_ENTER(db); + dn = DB_DNODE(db); + err = dmu_buf_hold_by_dnode(dn, offset, tag, dbp, flags); + DB_DNODE_EXIT(db); + + return (err); +} + int dmu_buf_hold(objset_t *os, uint64_t object, uint64_t offset, void *tag, dmu_buf_t **dbp, int flags) @@ -968,6 +985,33 @@ dmu_read_by_dnode(dnode_t *dn, uint64_t offset, uint64_t size, void *buf, return (dmu_read_impl(dn, offset, size, buf, flags)); } +/* + * Read 'size' bytes into the buffer. + * From object zdb->db_object. + * + * If the caller already has a dbuf in the target object + * (e.g. its bonus buffer), this routine is faster than dmu_read(), + * because we don't have to find the dnode_t for the object. + */ +int +dmu_read_by_dbuf(dmu_buf_t *zdb, uint64_t offset, uint64_t size, void *buf, + uint32_t flags) +{ + dmu_buf_impl_t *db = (dmu_buf_impl_t *)zdb; + dnode_t *dn; + int err; + + if (size == 0) + return (0); + + DB_DNODE_ENTER(db); + dn = DB_DNODE(db); + err = dmu_read_impl(dn, offset, size, buf, flags); + DB_DNODE_EXIT(db); + + return (err); +} + static void dmu_write_impl(dmu_buf_t **dbp, int numbufs, uint64_t offset, uint64_t size, const void *buf, dmu_tx_t *tx) diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c index 420282c4a494..270f6c006e8e 100644 --- a/module/zfs/zvol.c +++ b/module/zfs/zvol.c @@ -609,8 +609,8 @@ zvol_log_write(zvol_state_t *zv, dmu_tx_t *tx, uint64_t offset, itx = zil_itx_create(TX_WRITE, sizeof (*lr) + (write_state == WR_COPIED ? len : 0)); lr = (lr_write_t *)&itx->itx_lr; - if (write_state == WR_COPIED && dmu_read(zv->zv_objset, - ZVOL_OBJ, offset, len, lr+1, DMU_READ_NO_PREFETCH) != 0) { + if (write_state == WR_COPIED && dmu_read_by_dbuf(zv->zv_dbuf, + offset, len, lr+1, DMU_READ_NO_PREFETCH) != 0) { zil_itx_destroy(itx); itx = zil_itx_create(TX_WRITE, sizeof (*lr)); lr = (lr_write_t *)&itx->itx_lr; @@ -901,12 +901,12 @@ zvol_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio) * we don't have to write the data twice. */ if (buf != NULL) { /* immediate write */ - error = dmu_read(os, object, offset, size, buf, + error = dmu_read_by_dbuf(zv->zv_dbuf, offset, size, buf, DMU_READ_NO_PREFETCH); } else { size = zv->zv_volblocksize; offset = P2ALIGN_TYPED(offset, size, uint64_t); - error = dmu_buf_hold(os, object, offset, zgd, &db, + error = dmu_buf_hold_by_dbuf(zv->zv_dbuf, offset, zgd, &db, DMU_READ_NO_PREFETCH); if (error == 0) { blkptr_t *obp = dmu_buf_get_blkptr(db);