static void *ileaf_resize(struct btree *btree, tuxkey_t inum, vleaf *base, unsigned newsize) { assert(ileaf_sniff(btree, base)); struct ileaf *leaf = base; assert(inum >= ibase(leaf)); be_u16 *dict = base + btree->sb->blocksize; unsigned at = inum - ibase(leaf); if (at >= btree->entries_per_leaf) return NULL; unsigned extend_empty = at < icount(leaf) ? 0 : at - icount(leaf) + 1; unsigned offset = at && icount(leaf) ? from_be_u16(*(dict - (at < icount(leaf) ? at : icount(leaf)))) : 0; unsigned size = at < icount(leaf) ? from_be_u16(*(dict - at - 1)) - offset : 0; int more = newsize - size; if (more > 0 && sizeof(*dict) * extend_empty + more > ileaf_free(btree, leaf)) return NULL; for (; extend_empty--; leaf->count = to_be_u16(from_be_u16(leaf->count) + 1)) *(dict - icount(leaf) - 1) = to_be_u16(atdict(dict, icount(leaf))); assert(icount(leaf)); unsigned itop = from_be_u16(*(dict - icount(leaf))); void *attrs = leaf->table + offset; printf("resize inum 0x%Lx at 0x%x from %x to %x\n", (L)inum, offset, size, newsize); assert(itop >= offset + size); memmove(attrs + newsize, attrs + size, itop - offset - size); for (int i = at + 1; i <= icount(leaf); i++) add_idict(dict - i, more); return attrs; }
static int ileaf_merge(struct btree *btree, void *vinto, void *vfrom) { struct ileaf *into = vinto, *from = vfrom; unsigned fromcount = icount(from); /* If "from" is empty, does nothing */ if (!fromcount) return 1; assert(ibase(from) > ibase(into)); tuxkey_t fromibase = ibase(from); unsigned count = icount(into); int hole = fromibase - ibase(into) + count; __be16 *dict = ileaf_dict(btree, into); __be16 *fromdict = ileaf_dict(btree, from); int need_size = hole * sizeof(*dict) + ileaf_need(btree, from); if (ileaf_free(btree, into) < need_size) return 0; /* Fill hole of dict until from_ibase */ unsigned limit = atdict(dict, count); __be16 __limit = cpu_to_be16(limit); while (hole--) { count++; *(dict - count) = __limit; } /* Copy data from "from" */ unsigned fromlimit = atdict(fromdict, fromcount); memcpy(into->table + limit, from->table, fromlimit); /* Adjust copying fromdict */ if (limit) { int i; for (i = 1; i <= fromcount; i++) add_idict(dict - i, limit); } veccopy(dict - count - fromcount, fromdict - fromcount, fromcount); into->count = cpu_to_be16(count + fromcount); return 1; }
static void ileaf_dump(struct btree *btree, void *vleaf) { if (!tux3_trace) return; struct ileaf_attr_ops *attr_ops = btree->ops->private_ops; struct ileaf *leaf = vleaf; inum_t inum = ibase(leaf); __be16 *dict = ileaf_dict(btree, leaf); unsigned offset = 0; trace_on("inode table block 0x%Lx/%i (%x bytes free)", ibase(leaf), icount(leaf), ileaf_free(btree, leaf)); for (int i = 0; i < icount(leaf); i++, inum++) { int limit = __atdict(dict, i + 1), size = limit - offset; if (!size) continue; if (size < 0) trace_on(" 0x%Lx: <corrupt>\n", inum); else if (!size) trace_on(" 0x%Lx: <empty>\n", inum); else if (attr_ops == &iattr_ops) { /* FIXME: this doesn't work in kernel */ struct tux3_inode tuxnode = {}; struct inode *inode = &tuxnode.vfs_inode; void *attrs = leaf->table + offset; inode->i_sb = vfs_sb(btree->sb), attr_ops->decode(btree, inode, attrs, size); free_xcache(inode); } offset = limit; } }
static void *ileaf_resize(struct btree *btree, tuxkey_t inum, void *vleaf, int newsize) { struct ileaf *ileaf = vleaf; __be16 *dict = ileaf_dict(btree, ileaf); unsigned count = icount(ileaf); tuxkey_t at = inum - ibase(ileaf); int extend_dict, offset, size; assert(inum >= ibase(ileaf)); /* Get existent attributes, and calculate expand/shrink size */ if (at + 1 > count) { /* Check size roughly to avoid overflow int */ if ((at + 1) * sizeof(*dict) >= btree->sb->blocksize) goto overflow; /* Need to extend dict */ extend_dict = (at + 1 - count) * sizeof(*dict); offset = atdict(dict, count); size = 0; } else { /* "at" is in dict, so get attr size */ extend_dict = 0; offset = atdict(dict, at); size = __atdict(dict, at + 1) - offset; } if (ileaf_free(btree, ileaf) < newsize - size + extend_dict) { overflow: return NULL; } /* Extend dict */ if (extend_dict) { __be16 limit = cpu_to_be16(atdict(dict, count)); while (count < at + 1) { count++; *(dict - count) = limit; } ileaf->count = cpu_to_be16(count); } void *attrs = ileaf->table + offset; if (newsize != size) { /* Expand/Shrink attr space */ unsigned limit = __atdict(dict, count); assert(limit >= offset + size); memmove(attrs + newsize, attrs + size, limit - offset - size); /* Adjust dict */ int diff = newsize - size; at++; while (at <= count) { add_idict(dict - at, diff); at++; } } return attrs; }
static void ileaf_dump(struct btree *btree, vleaf *vleaf) { struct sb *sb = btree->sb; struct ileaf *leaf = vleaf; inum_t inum = ibase(leaf); be_u16 *dict = vleaf + sb->blocksize; unsigned offset = 0; printf("inode table block 0x%Lx/%i (%x bytes free)\n", (L)ibase(leaf), icount(leaf), ileaf_free(btree, leaf)); //hexdump(dict - icount(leaf), icount(leaf) * 2); for (int i = -1; -i <= icount(leaf); i--, inum++) { int limit = from_be_u16(dict[i]), size = limit - offset; if (!size) continue; printf(" 0x%Lx: ", (L)inum); //printf("[%x] ", offset); if (size < 0) printf("<corrupt>\n"); else if (!size) printf("<empty>\n"); else { /* FIXME: this doesn't work in kernel */ struct inode inode = { .i_sb = vfs_sb(btree->sb) }; unsigned xsize = decode_xsize(&inode, leaf->table + offset, size); tux_inode(&inode)->xcache = xsize ? new_xcache(xsize) : NULL; decode_attrs(&inode, leaf->table + offset, size); dump_attrs(&inode); xcache_dump(&inode); free(tux_inode(&inode)->xcache); } offset = limit; } } void *ileaf_lookup(struct btree *btree, inum_t inum, struct ileaf *leaf, unsigned *result) { assert(inum >= ibase(leaf)); assert(inum < ibase(leaf) + btree->entries_per_leaf); unsigned at = inum - ibase(leaf), size = 0; void *attrs = NULL; printf("lookup inode 0x%Lx, %Lx + %x\n", (L)inum, (L)ibase(leaf), at); if (at < icount(leaf)) { be_u16 *dict = (void *)leaf + btree->sb->blocksize; unsigned offset = atdict(dict, at); if ((size = from_be_u16(*(dict - at - 1)) - offset)) attrs = leaf->table + offset; } *result = size; return attrs; }