From e644b976b0b4140933644e7725ac372438adb18c Mon Sep 17 00:00:00 2001 From: Andriy Gapon Date: Tue, 11 Sep 2012 07:12:48 +0000 Subject: [PATCH] zfs boot: fix/replace fzap_rlookup implementation The previous one was totally bogus as it used hash value of _output_ variable as an index for searching... The only reliable way to do a reverse lookup here is to iterate over all entries. MFC after: 15 days --- sys/boot/zfs/zfsimpl.c | 67 +++++++++++++----------------------------- 1 file changed, 20 insertions(+), 47 deletions(-) diff --git a/sys/boot/zfs/zfsimpl.c b/sys/boot/zfs/zfsimpl.c index d60418d0a5f2..65a1803faaea 100644 --- a/sys/boot/zfs/zfsimpl.c +++ b/sys/boot/zfs/zfsimpl.c @@ -1581,9 +1581,7 @@ fzap_rlookup(const spa_t *spa, const dnode_phys_t *dnode, char *name, uint64_t v int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; zap_phys_t zh = *(zap_phys_t *) zap_scratch; fat_zap_t z; - uint64_t *ptrtbl; - uint64_t hash; - int rc; + int i, j; if (zh.zap_magic != ZAP_MAGIC) return (EIO); @@ -1592,59 +1590,34 @@ fzap_rlookup(const spa_t *spa, const dnode_phys_t *dnode, char *name, uint64_t v z.zap_phys = (zap_phys_t *) zap_scratch; /* - * Figure out where the pointer table is and read it in if necessary. + * This assumes that the leaf blocks start at block 1. The + * documentation isn't exactly clear on this. */ - if (zh.zap_ptrtbl.zt_blk) { - rc = dnode_read(spa, dnode, zh.zap_ptrtbl.zt_blk * bsize, - zap_scratch, bsize); - if (rc) - return (rc); - ptrtbl = (uint64_t *) zap_scratch; - } else { - ptrtbl = &ZAP_EMBEDDED_PTRTBL_ENT(&z, 0); - } - - hash = zap_hash(zh.zap_salt, name); - zap_leaf_t zl; zl.l_bs = z.zap_block_shift; + for (i = 0; i < zh.zap_num_leafs; i++) { + off_t off = (i + 1) << zl.l_bs; - off_t off = ptrtbl[hash >> (64 - zh.zap_ptrtbl.zt_shift)] << zl.l_bs; - zap_leaf_chunk_t *zc; + if (dnode_read(spa, dnode, off, zap_scratch, bsize)) + return (EIO); - rc = dnode_read(spa, dnode, off, zap_scratch, bsize); - if (rc) - return (rc); + zl.l_phys = (zap_leaf_phys_t *) zap_scratch; - zl.l_phys = (zap_leaf_phys_t *) zap_scratch; + for (j = 0; j < ZAP_LEAF_NUMCHUNKS(&zl); j++) { + zap_leaf_chunk_t *zc; - /* - * Make sure this chunk matches our hash. - */ - if (zl.l_phys->l_hdr.lh_prefix_len > 0 - && zl.l_phys->l_hdr.lh_prefix - != hash >> (64 - zl.l_phys->l_hdr.lh_prefix_len)) - return (ENOENT); + zc = &ZAP_LEAF_CHUNK(&zl, j); + if (zc->l_entry.le_type != ZAP_CHUNK_ENTRY) + continue; + if (zc->l_entry.le_value_intlen != 8 || + zc->l_entry.le_value_numints != 1) + continue; - /* - * Hash within the chunk to find our entry. - */ - int shift = (64 - ZAP_LEAF_HASH_SHIFT(&zl) - zl.l_phys->l_hdr.lh_prefix_len); - int h = (hash >> shift) & ((1 << ZAP_LEAF_HASH_SHIFT(&zl)) - 1); - h = zl.l_phys->l_hash[h]; - if (h == 0xffff) - return (ENOENT); - zc = &ZAP_LEAF_CHUNK(&zl, h); - while (zc->l_entry.le_hash != hash) { - if (zc->l_entry.le_next == 0xffff) { - zc = 0; - break; + if (fzap_leaf_value(&zl, zc) == value) { + fzap_name_copy(&zl, zc, name); + return (0); + } } - zc = &ZAP_LEAF_CHUNK(&zl, zc->l_entry.le_next); - } - if (fzap_leaf_value(&zl, zc) == value) { - fzap_name_copy(&zl, zc, name); - return (0); } return (ENOENT);