if (chain->bp) {
chain->data = NULL;
if (chain->flags & (HAMMER2_CHAIN_MODIFIED |
- HAMMER2_CHAIN_FLUSHED))
- bdwrite(chain->bp);
- else
+ HAMMER2_CHAIN_FLUSHED)) {
+ if (chain->flags & HAMMER2_CHAIN_IOFLUSH)
+ bawrite(chain->bp);
+ else
+ bdwrite(chain->bp);
+ } else {
bqrelse(chain->bp);
+ }
chain->bp = NULL;
}
lockmgr(&chain->lk, LK_RELEASE);
* typically points to an inode but can also point to a related indirect
* block and this function will recurse upwards and find the inode again.
*
+ * WARNING! THIS DOES NOT RETURN KEYS IN LOGICAL KEY ORDER! ANY KEY
+ * WITHIN THE RANGE CAN BE RETURNED. HOWEVER, AN ITERATION
+ * WHICH PICKS UP WHERE WE LEFT OFF WILL CONTINUE THE SCAN.
+ *
* (*parentp) must be exclusively locked and referenced and can be an inode
* or an existing indirect block within the inode.
*
return (NULL);
} else {
/*
- * Continue iteration with next parent
+ * Continue iteration with next parent unless the current
+ * parent covers the range.
*/
hammer2_chain_t *nparent;
if (parent->bref.type != HAMMER2_BREF_TYPE_INDIRECT)
return (NULL);
+
+ scan_beg = parent->bref.key;
+ scan_end = scan_beg +
+ ((hammer2_key_t)1 << parent->bref.keybits) - 1;
+ if (key_beg >= scan_beg && key_end <= scan_end)
+ return (NULL);
+
i = parent->index + 1;
nparent = parent->parent;
hammer2_chain_ref(hmp, nparent); /* ref new parent */
++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)
/*
* Create and return a new hammer2 system memory structure of the specified
- * key, type and size and insert it under (parent). (parent) is typically
- * acquired as a side effect of issuing a prior lookup. parent must be locked
- * and held.
+ * key, type and size and insert it RELATIVE TO (PARENT).
+ *
+ * (parent) is typically either an inode or an indirect block, acquired
+ * acquired as a side effect of issuing a prior failed lookup. parent
+ * must be locked and held. Do not pass the inode chain to this function
+ * unless that is the chain returned by the failed lookup.
*
* Non-indirect types will automatically allocate indirect blocks as required
* if the new item does not fit in the current (parent).
}
/*
- * Expand are calculated key range (key, keybits) to fit
- * the scanned key.
+ * Expand our calculated key range (key, keybits) to fit
+ * the scanned key. nkeybits represents the full range
+ * that we will later cut in half (two halves @ nkeybits - 1).
*/
nkeybits = keybits;
if (nkeybits < bref->keybits)
}
/*
- * The key for the indirect block will be the lower half or
- * the upper half of the above calculated keyspace.
+ * Adjust keybits to represent half of the full range calculated
+ * above.
+ */
+ --keybits;
+
+ /*
+ * Select whichever half contains the most elements. Theoretically
+ * we can select either side as long as it contains at least one
+ * element (in order to ensure that a free slot is present to hold
+ * the indirect block).
*/
key &= ~(((hammer2_key_t)1 << keybits) - 1);
if (hammer2_indirect_optimize) {
/*
- * Insert node for least number of keys, best for linear
- * files (?) XXX won't work if least number is 0.
+ * Insert node for least number of keys, this will arrange
+ * the first few blocks of a large file or the first few
+ * inodes in a directory with fewer indirect blocks when
+ * created linearly.
*/
- panic("hammer2_indirect_optimize not working yet");
- if (hicount < locount)
- key |= (hammer2_key_t)1 << (keybits - 1);
+ if (hicount < locount && hicount != 0)
+ key |= (hammer2_key_t)1 << keybits;
+ else
+ key &= ~(hammer2_key_t)1 << keybits;
} else {
/*
* Insert node for most number of keys, best for heavily
* fragmented files.
*/
if (hicount > locount)
- key |= (hammer2_key_t)1 << (keybits - 1);
+ key |= (hammer2_key_t)1 << keybits;
+ else
+ key &= ~(hammer2_key_t)1 << keybits;
}
/*
*/
dummy.bref.type = HAMMER2_BREF_TYPE_INDIRECT;
dummy.bref.key = key;
- dummy.bref.keybits = keybits - 1;
+ dummy.bref.keybits = keybits;
dummy.bref.data_off = (hammer2_off_t)
hammer2_freemap_bytes_to_radix(HAMMER2_PBUFSIZE);
- dummy.index = -1; /* not yet assigned */
ichain = hammer2_chain_alloc(hmp, &dummy.bref);
- kprintf("create_indirect2: allocate %016jx/%d\n", key, keybits);
/*
* Iterate the original parent and move the matching brefs into
- * the new indirect block. All the keys are inclusive of keybits
- * so we only have to check bit (keybits - 1).
+ * the new indirect block.
*/
for (i = 0; i < count; ++i) {
+ /*
+ * For keying purposes access the bref from the media or
+ * from our in-memory cache. In cases where the in-memory
+ * cache overrides the media the keyrefs will be the same
+ * anyway so we can avoid checking the cache when the media
+ * has a key.
+ */
bref = &base[i];
if (bref->type == 0) {
dummy.index = i;
* (keybits - 1) needs to be compared but for safety we
* will compare all msb bits plus that bit again.
*/
- if ((~(((hammer2_key_t)1 << (keybits - 1)) - 1) &
+ if ((~(((hammer2_key_t)1 << keybits) - 1) &
(key ^ bref->key)) != 0) {
continue;
}
*/
if (ichain->index < 0)
ichain->index = i;
- bzero(&base[i], sizeof(base[i]));
/*
* Load the new indirect block by acquiring or allocating
if (SPLAY_INSERT(hammer2_chain_splay, &ichain->shead, chain))
panic("hammer2_chain_create_indirect: collision");
chain->parent = ichain;
+ bzero(&base[i], sizeof(base[i]));
atomic_add_int(&parent->refs, -1);
atomic_add_int(&ichain->refs, 1);
if (chain->flags & HAMMER2_CHAIN_MOVED) {
* insertion index in the loop above (ichain->index).
*/
KKASSERT(ichain->index >= 0);
- kprintf("insert ichain at %d\n", ichain->index);
if (SPLAY_INSERT(hammer2_chain_splay, &parent->shead, ichain))
panic("hammer2_chain_create_indirect: ichain insertion");
ichain->parent = parent;
* return the original parent.
*/
hammer2_chain_put(hmp, ichain);
- } else if (~(((hammer2_key_t)1 << (keybits - 1)) - 1) &
+ } else if (~(((hammer2_key_t)1 << keybits) - 1) &
(create_key ^ key)) {
/*
* Key being created is outside the key range,
parent = ichain;
}
- kprintf("create_indirect9\n");
-
return(parent);
}
* allow '..' to cross the mount point into (e.g.) the super-root.
*/
error = 0;
- chain = (void *)(intptr_t)-1; /* non-NULL early done means not eof */
+ chain = (void *)(intptr_t)-1; /* non-NULL for early goto done case */
if (saveoff == 0) {
r = vop_write_dirent(&error, uio,
hammer2_chain_put(hmp, parent);
goto done;
}
- chain = hammer2_chain_lookup(hmp, &parent, lkey, (hammer2_key_t)-1, 0);
+ chain = hammer2_chain_lookup(hmp, &parent, lkey, lkey, 0);
+ if (chain == NULL) {
+ chain = hammer2_chain_lookup(hmp, &parent,
+ lkey, (hammer2_key_t)-1, 0);
+ }
while (chain) {
if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) {
dtype = hammer2_get_dtype(chain->u.ip);
done:
if (ap->a_eofflag)
*ap->a_eofflag = (chain == NULL);
- uio->uio_offset = saveoff;
+ uio->uio_offset = saveoff & ~HAMMER2_DIRHASH_VISIBLE;
if (error && cookie_index == 0) {
if (cookies) {
kfree(cookies, M_TEMP);
return vop_stdopen(ap);
}
+/*
+ * hammer_vop_advlock { vp, id, op, fl, flags }
+ *
+ * MPSAFE - does not require fs_token
+ */
+static
+int
+hammer2_vop_advlock(struct vop_advlock_args *ap)
+{
+ hammer2_inode_t *ip = VTOI(ap->a_vp);
+
+ return (lf_advlock(ap, &ip->advlock, ip->ip_data.size));
+}
+
+
static
int
hammer2_vop_close(struct vop_close_args *ap)
if (chain) {
hammer2_chain_modify(hmp, chain);
bcopy(bp->b_data, chain->data->buf + off_lo, bp->b_bcount);
- hammer2_chain_put(hmp, chain);
} else {
chain = hammer2_chain_create(hmp, parent,
off_hi, HAMMER2_PBUFRADIX,
HAMMER2_BREF_TYPE_DATA,
HAMMER2_PBUFSIZE);
bcopy(bp->b_data, chain->data->buf + off_lo, bp->b_bcount);
- hammer2_chain_put(hmp, chain);
}
+ if (off_lo + bp->b_bcount == HAMMER2_PBUFSIZE)
+ atomic_set_int(&chain->flags, HAMMER2_CHAIN_IOFLUSH);
+ hammer2_chain_put(hmp, chain);
hammer2_chain_put(hmp, parent);
bp->b_resid = 0;
.vop_getpages = vop_stdgetpages,
.vop_putpages = vop_stdputpages,
.vop_access = hammer2_vop_access,
+ .vop_advlock = hammer2_vop_advlock,
.vop_close = hammer2_vop_close,
.vop_ncreate = hammer2_vop_ncreate,
.vop_getattr = hammer2_vop_getattr,