summaryrefslogtreecommitdiffstats
path: root/sys/boot/zfs
diff options
context:
space:
mode:
authoravg <avg@FreeBSD.org>2012-09-11 07:12:48 +0000
committeravg <avg@FreeBSD.org>2012-09-11 07:12:48 +0000
commit85d585add4968eaa5f5ab5ff70e993f69fc587d6 (patch)
tree915c06835b45c891f8ed541c93cee8aedb9e2782 /sys/boot/zfs
parent1f8a1146b82a78a1b869195797eecc84d23a3a3a (diff)
downloadFreeBSD-src-85d585add4968eaa5f5ab5ff70e993f69fc587d6.zip
FreeBSD-src-85d585add4968eaa5f5ab5ff70e993f69fc587d6.tar.gz
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
Diffstat (limited to 'sys/boot/zfs')
-rw-r--r--sys/boot/zfs/zfsimpl.c67
1 files changed, 20 insertions, 47 deletions
diff --git a/sys/boot/zfs/zfsimpl.c b/sys/boot/zfs/zfsimpl.c
index d60418d..65a1803 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);
OpenPOWER on IntegriCloud