diff options
Diffstat (limited to 'module')
-rw-r--r-- | module/zfs/arc.c | 24 | ||||
-rw-r--r-- | module/zfs/dbuf.c | 18 |
2 files changed, 31 insertions, 11 deletions
diff --git a/module/zfs/arc.c b/module/zfs/arc.c index 2c7abe6ec..b42bb4050 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -1434,12 +1434,12 @@ arc_space_return(uint64_t space, arc_space_type_t type) } arc_buf_t * -arc_buf_alloc(spa_t *spa, int size, void *tag, arc_buf_contents_t type) +arc_buf_alloc(spa_t *spa, uint64_t size, void *tag, arc_buf_contents_t type) { arc_buf_hdr_t *hdr; arc_buf_t *buf; - ASSERT3U(size, >, 0); + VERIFY3U(size, <=, SPA_MAXBLOCKSIZE); hdr = kmem_cache_alloc(hdr_cache, KM_PUSHPAGE); ASSERT(BUF_EMPTY(hdr)); hdr->b_size = size; @@ -1477,7 +1477,7 @@ static char *arc_onloan_tag = "onloan"; * freed. */ arc_buf_t * -arc_loan_buf(spa_t *spa, int size) +arc_loan_buf(spa_t *spa, uint64_t size) { arc_buf_t *buf; @@ -1837,7 +1837,7 @@ arc_buf_remove_ref(arc_buf_t *buf, void* tag) return (no_callback); } -int +uint64_t arc_buf_size(arc_buf_t *buf) { return (buf->b_hdr->b_size); @@ -3307,6 +3307,22 @@ top: enum zio_compress b_compress = ZIO_COMPRESS_OFF; uint64_t b_asize = 0; + /* + * Gracefully handle a damaged logical block size as a + * checksum error by passing a dummy zio to the done callback. + */ + if (size > SPA_MAXBLOCKSIZE) { + if (done) { + rzio = zio_null(pio, spa, NULL, + NULL, NULL, zio_flags); + rzio->io_error = ECKSUM; + done(rzio, buf, private); + zio_nowait(rzio); + } + rc = ECKSUM; + goto out; + } + if (hdr == NULL) { /* this block is not in the cache */ arc_buf_hdr_t *exists = NULL; diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c index 76a8a99ab..b31957094 100644 --- a/module/zfs/dbuf.c +++ b/module/zfs/dbuf.c @@ -571,12 +571,13 @@ dbuf_read_done(zio_t *zio, arc_buf_t *buf, void *vdb) dbuf_rele_and_unlock(db, NULL); } -static void +static int dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t *flags) { dnode_t *dn; zbookmark_phys_t zb; uint32_t aflags = ARC_NOWAIT; + int err; DB_DNODE_ENTER(db); dn = DB_DNODE(db); @@ -601,7 +602,7 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t *flags) dbuf_update_data(db); db->db_state = DB_CACHED; mutex_exit(&db->db_mtx); - return; + return (0); } /* @@ -621,7 +622,7 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t *flags) db->db_state = DB_CACHED; *flags |= DB_RF_CACHED; mutex_exit(&db->db_mtx); - return; + return (0); } DB_DNODE_EXIT(db); @@ -640,12 +641,14 @@ dbuf_read_impl(dmu_buf_impl_t *db, zio_t *zio, uint32_t *flags) dbuf_add_ref(db, NULL); - (void) arc_read(zio, db->db_objset->os_spa, db->db_blkptr, + err = arc_read(zio, db->db_objset->os_spa, db->db_blkptr, dbuf_read_done, db, ZIO_PRIORITY_SYNC_READ, (*flags & DB_RF_CANFAIL) ? ZIO_FLAG_CANFAIL : ZIO_FLAG_MUSTSUCCEED, &aflags, &zb); if (aflags & ARC_CACHED) *flags |= DB_RF_CACHED; + + return (SET_ERROR(err)); } int @@ -688,11 +691,12 @@ dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags) if (zio == NULL) zio = zio_root(spa, NULL, NULL, ZIO_FLAG_CANFAIL); - dbuf_read_impl(db, zio, &flags); + + err = dbuf_read_impl(db, zio, &flags); /* dbuf_read_impl has dropped db_mtx for us */ - if (prefetch) + if (!err && prefetch) dmu_zfetch(&dn->dn_zfetch, db->db.db_offset, db->db.db_size, flags & DB_RF_CACHED); @@ -700,7 +704,7 @@ dbuf_read(dmu_buf_impl_t *db, zio_t *zio, uint32_t flags) rw_exit(&dn->dn_struct_rwlock); DB_DNODE_EXIT(db); - if (!havepzio) + if (!err && !havepzio) err = zio_wait(zio); } else { /* |