if (SPLAY_INSERT(hammer2_chain_splay, &parent->shead, chain))
panic("hammer2_chain_link: collision");
KKASSERT(parent->refs > 1);
- atomic_add_int(&parent->refs, 1);
+ atomic_add_int(&parent->refs, 1); /* for splay entry */
/*
* Additional linkage for inodes. Reuse the parent pointer to
if ((flags & HAMMER2_LOOKUP_NOLOCK) == 0)
hammer2_chain_lock(hmp, chain);
lockmgr(&chain->lk, LK_RELEASE);
- /* still locked */
return (chain);
}
count = HAMMER2_SET_COUNT;
break;
case HAMMER2_BREF_TYPE_INDIRECT:
+ if (parent->data == NULL)
+ panic("parent->data is NULL");
base = &parent->data->npdata.blockref[0];
count = HAMMER2_IND_COUNT;
break;
bref = (tmp) ? &tmp->bref : &base[i];
if (bref->type == 0)
continue;
- kprintf("lookup(%016jx,%d) %d: %016jx/%d\n",
- parent->bref.data_off, i,
- bref->type,bref->key, bref->keybits);
scan_beg = bref->key;
scan_end = scan_beg + ((hammer2_key_t)1 << bref->keybits) - 1;
if (key_beg <= scan_end && key_end >= scan_beg)
break;
}
- kprintf("lookup scan %d\n", i);
if (i == count) {
if (key_beg == key_end)
return (NULL);
/*
* If the chain element is an indirect block it becomes the new
- * parent and we loop on it.
+ * parent and we loop on it. We must fixup the chain we loop on
+ * if the caller passed flags to us that aren't sufficient for our
+ * needs.
*/
if (chain->bref.type == HAMMER2_BREF_TYPE_INDIRECT) {
hammer2_chain_put(hmp, parent);
*parentp = parent = chain;
+ if (flags & HAMMER2_LOOKUP_NOLOCK)
+ hammer2_chain_lock(hmp, chain);
goto again;
}
nparent = parent->parent;
hammer2_chain_ref(hmp, nparent); /* ref new parent */
hammer2_chain_unlock(hmp, parent);
- parent = nparent;
- hammer2_chain_lock(hmp, parent); /* lock new parent */
- hammer2_chain_drop(hmp, *parentp); /* drop old parent */
- *parentp = parent; /* new parent */
+ hammer2_chain_lock(hmp, nparent); /* lock new parent */
+ hammer2_chain_drop(hmp, parent); /* drop old parent */
+ *parentp = parent = nparent;
}
again2:
++i;
continue;
}
+#if 0
kprintf("nextxx(%016jx,%d) %d: %016jx/%d\n",
parent->bref.data_off, i,
bref->type,bref->key, bref->keybits);
+#endif
scan_beg = bref->key;
scan_end = scan_beg + ((hammer2_key_t)1 << bref->keybits) - 1;
if (key_beg <= scan_end && key_end >= scan_beg)
int count;
int i;
- kprintf("create_indirect1\n");
-
/*
* Mark the parent modified so our base[] pointer remains valid
* while we move entries.
++hicount;
else
++locount;
- kprintf("consolidate %016jx keybits %d lo %d hi %d\n",
- bref->key, keybits, locount, hicount);
}
/*
ichain->index = i;
continue;
}
- kprintf("pre-move index %d\n", i);
bref = &chain->bref;
}
* This element is being moved, its slot is available
* for our indirect block.
*/
- kprintf("move index %d\n", i);
if (ichain->index < 0)
ichain->index = i;
bzero(&base[i], sizeof(base[i]));
*
* Flagging the new chain entry MOVED will cause a flush
* to synchronize its block into the new indirect block.
- * We must still set SUBMODIFIED but we do that after the
- * loop.
+ * The chain is unlocked after being moved but needs to
+ * retain a reference for the MOVED state
+ *
+ * We must still set SUBMODIFIED in the parent but we do
+ * that after the loop.
+ *
+ * XXX we really need a lock here but we don't need the
+ * data. NODATA feature needed.
*/
chain = hammer2_chain_get(hmp, parent, i,
HAMMER2_LOOKUP_NOLOCK);
if (SPLAY_INSERT(hammer2_chain_splay, &ichain->shead, chain))
panic("hammer2_chain_create_indirect: collision");
chain->parent = ichain;
- atomic_set_int(&chain->flags, HAMMER2_CHAIN_MOVED);
atomic_add_int(&parent->refs, -1);
atomic_add_int(&ichain->refs, 1);
- hammer2_chain_drop(hmp, chain);
+ if (chain->flags & HAMMER2_CHAIN_MOVED) {
+ hammer2_chain_drop(hmp, chain);
+ } else {
+ atomic_set_int(&chain->flags, HAMMER2_CHAIN_MOVED);
+ }
KKASSERT(parent->refs > 0);
chain = NULL;
}
} else {
KKASSERT(scan->index < count);
base[scan->index] = bref;
- atomic_clear_int(&scan->flags,
+ if (scan->flags & HAMMER2_CHAIN_MOVED) {
+ atomic_clear_int(&scan->flags,
HAMMER2_CHAIN_MOVED);
+ hammer2_chain_drop(hmp, scan);
+ }
}
hammer2_chain_put(hmp, scan);
}
hammer2_inode_t *ip;
hammer2_chain_t *parent;
hammer2_chain_t *chain;
- hammer2_key_t off_hi;
+ hammer2_key_t loff;
+ hammer2_off_t poff;
/*
* Only supported on regular files
ip = VTOI(vp);
hmp = ip->hmp;
- off_hi = ap->a_loffset & HAMMER2_OFF_MASK_HI;
- KKASSERT((ap->a_loffset & HAMMER2_LBUFMASK64) == 0);
+
+ loff = ap->a_loffset;
+ KKASSERT((loff & HAMMER2_LBUFMASK64) == 0);
parent = &ip->chain;
hammer2_chain_ref(hmp, parent);
hammer2_chain_lock(hmp, parent);
- chain = hammer2_chain_lookup(hmp, &parent, off_hi, off_hi, 0);
+ chain = hammer2_chain_lookup(hmp, &parent, loff, loff, 0);
if (chain) {
- *ap->a_doffsetp = (chain->bref.data_off & ~HAMMER2_LBUFMASK64);
+ poff = loff - chain->bref.key +
+ (chain->bref.data_off & HAMMER2_OFF_MASK);
+ *ap->a_doffsetp = poff;
hammer2_chain_put(hmp, chain);
} else {
*ap->a_doffsetp = ZFOFFSET; /* zero-fill hole */
hammer2_inode_t *ip;
hammer2_chain_t *parent;
hammer2_chain_t *chain;
- hammer2_key_t off_hi;
+ hammer2_key_t loff;
+ hammer2_off_t poff;
bio = ap->a_bio;
bp = bio->bio_buf;
nbio = push_bio(bio);
if (nbio->bio_offset == NOOFFSET) {
- off_hi = bio->bio_offset & HAMMER2_OFF_MASK_HI;
- KKASSERT((bio->bio_offset & HAMMER2_LBUFMASK64) == 0);
+ loff = bio->bio_offset;
+ KKASSERT((loff & HAMMER2_LBUFMASK64) == 0);
parent = &ip->chain;
hammer2_chain_ref(hmp, parent);
* chain element's content. We just need the block device
* offset.
*/
- kprintf("lookup data logical %016jx\n", off_hi);
- chain = hammer2_chain_lookup(hmp, &parent, off_hi, off_hi,
+ chain = hammer2_chain_lookup(hmp, &parent, loff, loff,
HAMMER2_LOOKUP_NOLOCK);
if (chain) {
- kprintf("lookup success\n");
- nbio->bio_offset = (chain->bref.data_off &
- ~HAMMER2_LBUFMASK64);
+ poff = loff - chain->bref.key +
+ (chain->bref.data_off & HAMMER2_OFF_MASK);
+ nbio->bio_offset = poff;
hammer2_chain_drop(hmp, chain);
} else {
- kprintf("lookup zero-fill\n");
nbio->bio_offset = ZFOFFSET;
}
hammer2_chain_put(hmp, parent);
vfs_bio_clrbuf(bp);
biodone(nbio);
} else {
- kprintf("data read %016jx\n", nbio->bio_offset);
vn_strategy(hmp->devvp, nbio);
}
return (0);
.vop_ncreate = hammer2_vop_ncreate,
.vop_getattr = hammer2_vop_getattr,
.vop_readdir = hammer2_vop_readdir,
+ .vop_getpages = vop_stdgetpages,
+ .vop_putpages = vop_stdputpages,
.vop_read = hammer2_vop_read,
.vop_write = hammer2_vop_write,
.vop_open = hammer2_vop_open,