Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

hammer2 - Start working on the freemap (note: freemap not yet operati…

…onal)

* hammer2 show now tries to dump all four volume headers

* Minimum storage allocation chunk size is 1K, increase MIN_RADIX and
  MIN_ALLOC appropriately.

* Preliminary reserved block mappings for the freemap indirect and bitmap
  blocks.

* Preliminary freemap design will use normal indirect blocks (but with
  a different bref.type name).  The check area of the bref will be used to
  store additional freemap hints.

  The volume header will contain a blockref to the root of the freemap,
  and newfs_hammer2 now initializes this blockref.

* Bring major hammer2_disk.h media structure comments up to snuff.

* Formalize blockref.methods and set proper defaults.  This field contains
  the crc/check and compression methods for a blockref.
  • Loading branch information...
commit 9061bde5ad5e46bcaee746ed03d598a75b38691f 1 parent 63f86bf
Matthew Dillon authored
View
11 sbin/hammer2/cmd_debug.c
@@ -315,16 +315,19 @@ cmd_show(const char *devpath)
{
hammer2_blockref_t broot;
int fd;
+ int i;
fd = open(devpath, O_RDONLY);
if (fd < 0) {
perror("open");
return 1;
}
- bzero(&broot, sizeof(broot));
- broot.type = HAMMER2_BREF_TYPE_VOLUME;
- broot.data_off = 0 | HAMMER2_PBUFRADIX;
- show_bref(fd, 0, 0, &broot);
+ for (i = 0; i < 4; ++i) {
+ bzero(&broot, sizeof(broot));
+ broot.type = HAMMER2_BREF_TYPE_VOLUME;
+ broot.data_off = (i * HAMMER2_ZONE_BYTES64) | HAMMER2_PBUFRADIX;
+ show_bref(fd, 0, i, &broot);
+ }
close(fd);
return 0;
View
69 sbin/newfs_hammer2/newfs_hammer2.c
@@ -452,6 +452,7 @@ format_hammer2(int fd, hammer2_off_t total_space, hammer2_off_t free_space)
hammer2_inode_data_t *rawip;
hammer2_blockref_t sroot_blockref;
hammer2_blockref_t root_blockref;
+ hammer2_blockref_t freemap_blockref;
uint64_t now;
hammer2_off_t volu_base = 0;
hammer2_off_t boot_base = HAMMER2_ZONE_SEG;
@@ -484,10 +485,14 @@ format_hammer2(int fd, hammer2_off_t total_space, hammer2_off_t free_space)
}
/*
+ * Make sure alloc_base won't cross the reserved area at the
+ * beginning of each 2GB zone.
+ *
* Reserve space for the super-root inode and the root inode.
- * Put them in the same 64K block.
+ * Make sure they are in the same 64K block to simplify our code.
*/
assert((alloc_base & HAMMER2_PBUFMASK) == 0);
+ assert(alloc_base < HAMMER2_ZONE_BYTES64 - HAMMER2_ZONE_SEG);
alloc_base &= ~HAMMER2_PBUFMASK64;
alloc_direct(&alloc_base, &sroot_blockref, HAMMER2_INODE_BYTES);
@@ -541,8 +546,8 @@ format_hammer2(int fd, hammer2_off_t total_space, hammer2_off_t free_space)
root_blockref.check.iscsi32.value =
hammer2_icrc32(rawip, sizeof(*rawip));
root_blockref.type = HAMMER2_BREF_TYPE_INODE;
- root_blockref.methods = HAMMER2_ENC_CHECKMETHOD(HAMMER2_CHECK_ICRC) |
- HAMMER2_ENC_COMPMETHOD(HAMMER2_COMP_AUTOZERO);
+ root_blockref.methods = HAMMER2_ENC_CHECK(HAMMER2_CHECK_ISCSI32) |
+ HAMMER2_ENC_COMP(HAMMER2_COMP_AUTOZERO);
/*
* Format the super-root directory inode, giving it one directory
@@ -593,8 +598,9 @@ format_hammer2(int fd, hammer2_off_t total_space, hammer2_off_t free_space)
sroot_blockref.check.iscsi32.value =
hammer2_icrc32(rawip, sizeof(*rawip));
sroot_blockref.type = HAMMER2_BREF_TYPE_INODE;
- sroot_blockref.methods = HAMMER2_ENC_CHECKMETHOD(HAMMER2_CHECK_ICRC) |
- HAMMER2_ENC_COMPMETHOD(HAMMER2_COMP_AUTOZERO);
+ sroot_blockref.methods = HAMMER2_ENC_CHECK(HAMMER2_CHECK_ISCSI32) |
+ HAMMER2_ENC_COMP(HAMMER2_COMP_AUTOZERO);
+ rawip = NULL;
/*
* Write out the 64K HAMMER2 block containing the root and sroot.
@@ -607,6 +613,58 @@ format_hammer2(int fd, hammer2_off_t total_space, hammer2_off_t free_space)
}
/*
+ * Set up the freemap blockref. This blockref must point to the
+ * appropriate reserved block (ZONE_FREEMAP_A + ZONEFM_LAYER0).
+ * We use a special check method CHECK_FREEMAP which is basically
+ * just CHECK_ISCSI32 but contains additional hinting fields to
+ * help the allocator.
+ *
+ * Even though the freemap is multi-level, all newfs2_hammer2 needs
+ * to do is set up an empty root freemap indirect block. The HAMMER2
+ * VFS will populate the remaining layers and leaf(s) on the fly.
+ *
+ * The root freemap indirect block must represent a space large enough
+ * to cover the whole filesystem. Since we are using normal
+ * blockref's, each indirect freemap block represents
+ * FREEMAP_NODE_RADIX (10) bits of address space. A 64KB leaf block
+ * represents FREEMAP_LEAF_REP (256MB) bytes of storage.
+ *
+ * For now we install a MAXIMAL key range to (potentially) support
+ * a sparse storage map by default. Only certain keybits values
+ * are allowed for the freemap root (64, 54, 44, or 34).
+ */
+ bzero(buf, HAMMER2_PBUFSIZE);
+ bzero(&freemap_blockref, sizeof(freemap_blockref));
+ freemap_blockref.vradix = HAMMER2_PBUFRADIX;
+ freemap_blockref.data_off = (HAMMER2_ZONE_FREEMAP_A +
+ HAMMER2_ZONEFM_LAYER0) |
+ HAMMER2_PBUFRADIX;
+ freemap_blockref.copyid = HAMMER2_COPYID_LOCAL;
+ freemap_blockref.keybits = 64;
+ freemap_blockref.type = HAMMER2_BREF_TYPE_FREEMAP_ROOT;
+ freemap_blockref.methods = HAMMER2_ENC_CHECK(HAMMER2_CHECK_FREEMAP) |
+ HAMMER2_ENC_COMP(HAMMER2_COMP_AUTOZERO);
+
+ /*
+ * check union also has hinting fields. We can just set the (biggest)
+ * heuristic to a maximal value and let the allocator adjust it,
+ * and we must initialize (avail) properly (taking into account
+ * reserved blocks) so auto-initialized sub-trees/leafs match up
+ * to expected values.
+ */
+ freemap_blockref.check.freemap.icrc32 =
+ hammer2_icrc32(buf, HAMMER2_PBUFSIZE);
+ freemap_blockref.check.freemap.biggest = 64;
+ freemap_blockref.check.freemap.avail = free_space;
+
+ n = pwrite(fd, buf, HAMMER2_PBUFSIZE,
+ freemap_blockref.data_off & HAMMER2_OFF_MASK_HI);
+ if (n != HAMMER2_PBUFSIZE) {
+ perror("write");
+ exit(1);
+ }
+
+ /*
* Format the volume header.
*
* The volume header points to sroot_blockref. Also be absolutely
@@ -634,6 +692,7 @@ format_hammer2(int fd, hammer2_off_t total_space, hammer2_off_t free_space)
vol->allocator_beg = alloc_base;
vol->sroot_blockset.blockref[0] = sroot_blockref;
+ vol->freemap_blockref = freemap_blockref;
vol->mirror_tid = 0;
vol->alloc_tid = 16;
vol->icrc_sects[HAMMER2_VOL_ICRC_SECT1] =
View
10 sys/vfs/hammer2/hammer2.h
@@ -78,6 +78,9 @@ struct hammer2_span;
struct hammer2_state;
struct hammer2_msg;
+struct hammer2_indblock;
+struct hammer2_data;
+
/*
* The chain structure tracks blockref recursions all the way to
* the root volume. These consist of indirect blocks, inodes,
@@ -270,6 +273,9 @@ struct hammer2_data {
typedef struct hammer2_data hammer2_data_t;
+/*
+ * XXX
+ */
struct hammer2_freecache {
hammer2_off_t bulk;
hammer2_off_t single;
@@ -358,6 +364,7 @@ extern long hammer2_iod_indr_read;
extern long hammer2_iod_file_write;
extern long hammer2_iod_meta_write;
extern long hammer2_iod_indr_write;
+extern long hammer2_iod_fmap_write;
extern long hammer2_iod_volu_write;
extern long hammer2_ioa_file_read;
extern long hammer2_ioa_meta_read;
@@ -365,6 +372,7 @@ extern long hammer2_ioa_indr_read;
extern long hammer2_ioa_file_write;
extern long hammer2_ioa_meta_write;
extern long hammer2_ioa_indr_write;
+extern long hammer2_ioa_fmap_write;
extern long hammer2_ioa_volu_write;
/*
@@ -395,7 +403,7 @@ u_int32_t hammer2_to_unix_xid(uuid_t *uuid);
void hammer2_guid_to_uuid(uuid_t *uuid, u_int32_t guid);
hammer2_key_t hammer2_dirhash(const unsigned char *name, size_t len);
-int hammer2_bytes_to_radix(size_t bytes);
+int hammer2_allocsize(size_t bytes);
int hammer2_calc_logical(hammer2_inode_t *ip, hammer2_off_t uoff,
hammer2_key_t *lbasep, hammer2_key_t *leofp);
View
90 sys/vfs/hammer2/hammer2_chain.c
@@ -139,11 +139,14 @@ hammer2_chain_alloc(hammer2_mount_t *hmp, hammer2_blockref_t *bref)
ip->hmp = hmp;
break;
case HAMMER2_BREF_TYPE_INDIRECT:
+ case HAMMER2_BREF_TYPE_FREEMAP_ROOT:
+ case HAMMER2_BREF_TYPE_FREEMAP_NODE:
np = kmalloc(sizeof(*np), hmp->mchain, M_WAITOK | M_ZERO);
chain = &np->chain;
chain->u.np = np;
break;
case HAMMER2_BREF_TYPE_DATA:
+ case HAMMER2_BREF_TYPE_FREEMAP_LEAF:
dp = kmalloc(sizeof(*dp), hmp->mchain, M_WAITOK | M_ZERO);
chain = &dp->chain;
chain->u.dp = dp;
@@ -517,6 +520,8 @@ hammer2_chain_lock(hammer2_mount_t *hmp, hammer2_chain_t *chain, int how)
return(0);
if (chain->bref.type == HAMMER2_BREF_TYPE_DATA)
return(0);
+ if (chain->bref.type == HAMMER2_BREF_TYPE_FREEMAP_LEAF)
+ return(0);
/* fall through */
case HAMMER2_RESOLVE_ALWAYS:
break;
@@ -627,6 +632,9 @@ hammer2_chain_lock(hammer2_mount_t *hmp, hammer2_chain_t *chain, int how)
break;
case HAMMER2_BREF_TYPE_INDIRECT:
case HAMMER2_BREF_TYPE_DATA:
+ case HAMMER2_BREF_TYPE_FREEMAP_ROOT:
+ case HAMMER2_BREF_TYPE_FREEMAP_NODE:
+ case HAMMER2_BREF_TYPE_FREEMAP_LEAF:
default:
/*
* Point data at the device buffer and leave bp intact.
@@ -701,6 +709,11 @@ hammer2_chain_unlock(hammer2_mount_t *hmp, hammer2_chain_t *chain)
case HAMMER2_BREF_TYPE_INDIRECT:
counterp = &hammer2_ioa_indr_write;
break;
+ case HAMMER2_BREF_TYPE_FREEMAP_ROOT:
+ case HAMMER2_BREF_TYPE_FREEMAP_NODE:
+ case HAMMER2_BREF_TYPE_FREEMAP_LEAF:
+ counterp = &hammer2_ioa_fmap_write;
+ break;
default:
counterp = &hammer2_ioa_volu_write;
break;
@@ -717,6 +730,11 @@ hammer2_chain_unlock(hammer2_mount_t *hmp, hammer2_chain_t *chain)
case HAMMER2_BREF_TYPE_INDIRECT:
counterp = &hammer2_iod_indr_write;
break;
+ case HAMMER2_BREF_TYPE_FREEMAP_ROOT:
+ case HAMMER2_BREF_TYPE_FREEMAP_NODE:
+ case HAMMER2_BREF_TYPE_FREEMAP_LEAF:
+ counterp = &hammer2_iod_fmap_write;
+ break;
default:
counterp = &hammer2_iod_volu_write;
break;
@@ -730,6 +748,9 @@ hammer2_chain_unlock(hammer2_mount_t *hmp, hammer2_chain_t *chain)
* If a device buffer was used for data be sure to destroy the
* buffer when we are done to avoid aliases (XXX what about the
* underlying VM pages?).
+ *
+ * NOTE: Freemap leaf's use reserved blocks and thus no aliasing
+ * is possible.
*/
if (chain->bref.type == HAMMER2_BREF_TYPE_DATA)
chain->bp->b_flags |= B_RELBUF;
@@ -803,7 +824,8 @@ hammer2_chain_resize(hammer2_inode_t *ip, hammer2_chain_t *chain,
int error;
/*
- * Only data and indirect blocks can be resized for now
+ * Only data and indirect blocks can be resized for now.
+ * (The volu root, inodes, and freemap elements use a fixed size).
*/
KKASSERT(chain != &hmp->vchain);
KKASSERT(chain->bref.type == HAMMER2_BREF_TYPE_DATA ||
@@ -1010,7 +1032,7 @@ hammer2_chain_modify(hammer2_mount_t *hmp, hammer2_chain_t *chain, int flags)
/*
* We currently should never instantiate a device buffer for a
- * data chain.
+ * file data chain. (We definitely can for a freemap chain).
*/
KKASSERT(chain->bref.type != HAMMER2_BREF_TYPE_DATA);
@@ -1028,6 +1050,9 @@ hammer2_chain_modify(hammer2_mount_t *hmp, hammer2_chain_t *chain, int flags)
break;
case HAMMER2_BREF_TYPE_DATA:
case HAMMER2_BREF_TYPE_INDIRECT:
+ case HAMMER2_BREF_TYPE_FREEMAP_ROOT:
+ case HAMMER2_BREF_TYPE_FREEMAP_NODE:
+ case HAMMER2_BREF_TYPE_FREEMAP_LEAF:
/*
* Perform the copy-on-write operation
*/
@@ -1191,6 +1216,8 @@ hammer2_chain_get(hammer2_mount_t *hmp, hammer2_chain_t *parent,
bref = &parent->data->ipdata.u.blockset.blockref[index];
break;
case HAMMER2_BREF_TYPE_INDIRECT:
+ case HAMMER2_BREF_TYPE_FREEMAP_ROOT:
+ case HAMMER2_BREF_TYPE_FREEMAP_NODE:
KKASSERT(parent->data != NULL);
KKASSERT(index >= 0 &&
index < parent->bytes / sizeof(hammer2_blockref_t));
@@ -1318,7 +1345,8 @@ hammer2_chain_lookup(hammer2_mount_t *hmp, hammer2_chain_t **parentp,
* encloses the key range or we hit the inode.
*/
parent = *parentp;
- while (parent->bref.type == HAMMER2_BREF_TYPE_INDIRECT) {
+ while (parent->bref.type == HAMMER2_BREF_TYPE_INDIRECT ||
+ parent->bref.type == HAMMER2_BREF_TYPE_FREEMAP_NODE) {
scan_beg = parent->bref.key;
scan_end = scan_beg +
((hammer2_key_t)1 << parent->bref.keybits) - 1;
@@ -1358,6 +1386,8 @@ hammer2_chain_lookup(hammer2_mount_t *hmp, hammer2_chain_t **parentp,
count = HAMMER2_SET_COUNT;
break;
case HAMMER2_BREF_TYPE_INDIRECT:
+ case HAMMER2_BREF_TYPE_FREEMAP_ROOT:
+ case HAMMER2_BREF_TYPE_FREEMAP_NODE:
/*
* Optimize indirect blocks in the INITIAL state to avoid
* I/O.
@@ -1429,7 +1459,8 @@ hammer2_chain_lookup(hammer2_mount_t *hmp, hammer2_chain_t **parentp,
* The parent always has to be locked with at least RESOLVE_MAYBE,
* so it might need a fixup if the caller passed incompatible flags.
*/
- if (chain->bref.type == HAMMER2_BREF_TYPE_INDIRECT) {
+ if (chain->bref.type == HAMMER2_BREF_TYPE_INDIRECT ||
+ chain->bref.type == HAMMER2_BREF_TYPE_FREEMAP_NODE) {
hammer2_chain_unlock(hmp, parent);
*parentp = parent = chain;
if (flags & HAMMER2_LOOKUP_NOLOCK) {
@@ -1504,7 +1535,8 @@ hammer2_chain_next(hammer2_mount_t *hmp, hammer2_chain_t **parentp,
if (chain == parent)
return(NULL);
chain = NULL;
- } else if (parent->bref.type != HAMMER2_BREF_TYPE_INDIRECT) {
+ } else if (parent->bref.type != HAMMER2_BREF_TYPE_INDIRECT &&
+ parent->bref.type != HAMMER2_BREF_TYPE_FREEMAP_NODE) {
/*
* We reached the end of the iteration.
*/
@@ -1543,6 +1575,8 @@ hammer2_chain_next(hammer2_mount_t *hmp, hammer2_chain_t **parentp,
count = HAMMER2_SET_COUNT;
break;
case HAMMER2_BREF_TYPE_INDIRECT:
+ case HAMMER2_BREF_TYPE_FREEMAP_ROOT:
+ case HAMMER2_BREF_TYPE_FREEMAP_NODE:
if (parent->flags & HAMMER2_CHAIN_INITIAL) {
base = NULL;
} else {
@@ -1617,7 +1651,8 @@ hammer2_chain_next(hammer2_mount_t *hmp, hammer2_chain_t **parentp,
* The parent always has to be locked with at least RESOLVE_MAYBE,
* so it might need a fixup if the caller passed incompatible flags.
*/
- if (chain->bref.type == HAMMER2_BREF_TYPE_INDIRECT) {
+ if (chain->bref.type == HAMMER2_BREF_TYPE_INDIRECT ||
+ chain->bref.type == HAMMER2_BREF_TYPE_FREEMAP_NODE) {
hammer2_chain_unlock(hmp, parent);
*parentp = parent = chain;
chain = NULL;
@@ -1692,7 +1727,8 @@ hammer2_chain_create(hammer2_mount_t *hmp, hammer2_chain_t *parent,
dummy.type = type;
dummy.key = key;
dummy.keybits = keybits;
- dummy.data_off = hammer2_bytes_to_radix(bytes);
+ dummy.data_off = hammer2_allocsize(bytes);
+ dummy.methods = parent->bref.methods;
chain = hammer2_chain_alloc(hmp, &dummy);
allocated = 1;
@@ -1719,6 +1755,12 @@ hammer2_chain_create(hammer2_mount_t *hmp, hammer2_chain_t *parent,
panic("hammer2_chain_create: cannot be used to"
"create indirect block");
break;
+ case HAMMER2_BREF_TYPE_FREEMAP_ROOT:
+ case HAMMER2_BREF_TYPE_FREEMAP_NODE:
+ panic("hammer2_chain_create: cannot be used to"
+ "create freemap root or node");
+ break;
+ case HAMMER2_BREF_TYPE_FREEMAP_LEAF:
case HAMMER2_BREF_TYPE_DATA:
default:
/* leave chain->data NULL */
@@ -1746,6 +1788,8 @@ hammer2_chain_create(hammer2_mount_t *hmp, hammer2_chain_t *parent,
count = HAMMER2_SET_COUNT;
break;
case HAMMER2_BREF_TYPE_INDIRECT:
+ case HAMMER2_BREF_TYPE_FREEMAP_ROOT:
+ case HAMMER2_BREF_TYPE_FREEMAP_NODE:
if (parent->flags & HAMMER2_CHAIN_INITIAL) {
base = NULL;
} else {
@@ -1880,17 +1924,24 @@ hammer2_chain_create(hammer2_mount_t *hmp, hammer2_chain_t *parent,
* the data onto device buffers!).
*/
if (allocated) {
- if (chain->bref.type == HAMMER2_BREF_TYPE_DATA) {
+ switch(chain->bref.type) {
+ case HAMMER2_BREF_TYPE_DATA:
+ case HAMMER2_BREF_TYPE_FREEMAP_LEAF:
hammer2_chain_modify(hmp, chain,
HAMMER2_MODIFY_OPTDATA);
- } else if (chain->bref.type == HAMMER2_BREF_TYPE_INDIRECT) {
+ break;
+ case HAMMER2_BREF_TYPE_INDIRECT:
+ case HAMMER2_BREF_TYPE_FREEMAP_ROOT:
+ case HAMMER2_BREF_TYPE_FREEMAP_NODE:
/* not supported in this function */
panic("hammer2_chain_create: bad type");
atomic_set_int(&chain->flags, HAMMER2_CHAIN_INITIAL);
hammer2_chain_modify(hmp, chain,
HAMMER2_MODIFY_OPTDATA);
- } else {
+ break;
+ default:
hammer2_chain_modify(hmp, chain, 0);
+ break;
}
} else {
/*
@@ -1997,6 +2048,8 @@ hammer2_chain_create_indirect(hammer2_mount_t *hmp, hammer2_chain_t *parent,
count = HAMMER2_SET_COUNT;
break;
case HAMMER2_BREF_TYPE_INDIRECT:
+ case HAMMER2_BREF_TYPE_FREEMAP_ROOT:
+ case HAMMER2_BREF_TYPE_FREEMAP_NODE:
count = parent->bytes / sizeof(hammer2_blockref_t);
break;
case HAMMER2_BREF_TYPE_VOLUME:
@@ -2016,6 +2069,8 @@ hammer2_chain_create_indirect(hammer2_mount_t *hmp, hammer2_chain_t *parent,
count = HAMMER2_SET_COUNT;
break;
case HAMMER2_BREF_TYPE_INDIRECT:
+ case HAMMER2_BREF_TYPE_FREEMAP_ROOT:
+ case HAMMER2_BREF_TYPE_FREEMAP_NODE:
base = &parent->data->npdata.blockref[0];
count = parent->bytes / sizeof(hammer2_blockref_t);
break;
@@ -2145,10 +2200,19 @@ hammer2_chain_create_indirect(hammer2_mount_t *hmp, hammer2_chain_t *parent,
/*
* Ok, create our new indirect block
*/
- dummy.bref.type = HAMMER2_BREF_TYPE_INDIRECT;
+ switch(parent->bref.type) {
+ case HAMMER2_BREF_TYPE_FREEMAP_ROOT:
+ case HAMMER2_BREF_TYPE_FREEMAP_NODE:
+ dummy.bref.type = HAMMER2_BREF_TYPE_FREEMAP_NODE;
+ break;
+ default:
+ dummy.bref.type = HAMMER2_BREF_TYPE_INDIRECT;
+ break;
+ }
dummy.bref.key = key;
dummy.bref.keybits = keybits;
- dummy.bref.data_off = hammer2_bytes_to_radix(nbytes);
+ dummy.bref.data_off = hammer2_allocsize(nbytes);
+ dummy.bref.methods = parent->bref.methods;
ichain = hammer2_chain_alloc(hmp, &dummy.bref);
atomic_set_int(&ichain->flags, HAMMER2_CHAIN_INITIAL);
@@ -2384,6 +2448,8 @@ hammer2_chain_delete(hammer2_mount_t *hmp, hammer2_chain_t *parent,
count = HAMMER2_SET_COUNT;
break;
case HAMMER2_BREF_TYPE_INDIRECT:
+ case HAMMER2_BREF_TYPE_FREEMAP_ROOT:
+ case HAMMER2_BREF_TYPE_FREEMAP_NODE:
hammer2_chain_modify(hmp, parent, HAMMER2_MODIFY_OPTDATA |
HAMMER2_MODIFY_NO_MODIFY_TID);
if (parent->flags & HAMMER2_CHAIN_INITIAL)
View
368 sys/vfs/hammer2/hammer2_disk.h
@@ -60,14 +60,18 @@
/*
* The data at the end of a file or directory may be a fragment in order
- * to optimize storage efficiency. The minimum fragment size is 64 bytes.
+ * to optimize storage efficiency. The minimum fragment size is 1KB.
* Since allocations are in powers of 2 fragments must also be sized in
- * powers of 2 (64, 128, 256, ... 65536).
+ * powers of 2 (1024, 2048, ... 65536).
*
* For the moment the maximum allocation size is HAMMER2_PBUFSIZE (64K),
- * which is 2^16. Larger extents may be supported in the future.
+ * which is 2^16. Larger extents may be supported in the future. Smaller
+ * fragments might be supported in the future (down to 64 bytes is possible),
+ * but probably will not be.
*
- * A full indirect block uses supports 1024 x 64-byte blockrefs.
+ * A full indirect block use supports 1024 x 64-byte blockrefs in a 64KB
+ * buffer. Indirect blocks down to 1KB are supported to keep small
+ * directories small.
*
* A maximally sized file (2^64-1 bytes) requires 5 indirect block levels.
* The hammer2_blockset in the volume header or file inode has another 8
@@ -76,8 +80,8 @@
* currently supports up to 8 copies, which brings the address space down
* to 66 bits and gives us 2 bits of leeway.
*/
-#define HAMMER2_MIN_ALLOC 64 /* minimum allocation size */
-#define HAMMER2_MIN_RADIX 6 /* minimum allocation size 2^N */
+#define HAMMER2_MIN_ALLOC 1024 /* minimum allocation size */
+#define HAMMER2_MIN_RADIX 10 /* minimum allocation size 2^N */
#define HAMMER2_MAX_RADIX 16 /* maximum allocation size 2^N */
#define HAMMER2_KEY_RADIX 64 /* number of bits in key */
@@ -124,15 +128,20 @@
sizeof(hammer2_blockref_t))
/*
- * HAMMER2 processes blockrefs in sets of 8. The set is fully associative,
- * is not sorted, and may contain holes.
- *
- * A full indirect block supports 1024 blockrefs.
- *
- * An inode embeds one set of blockrefs but may also use the data area for
- * up to 512 bytes of direct data.
+ * In HAMMER2, arrays of blockrefs are fully set-associative, meaning that
+ * any element can occur at any index and holes can be anywhere. As a
+ * future optimization we will be able to flag that such arrays are sorted
+ * and thus optimize lookups, but for now we don't.
+ *
+ * Inodes embed either 512 bytes of direct data or an array of 8 blockrefs,
+ * resulting in highly efficient storage for files <= 512 bytes and for files
+ * <= 512KB. Up to 8 directory entries can be referenced from a directory
+ * without requiring an indirect block.
+ *
+ * Indirect blocks are typically either 4KB (64 blockrefs / ~4MB represented),
+ * or 64KB (1024 blockrefs / ~64MB represented).
*/
-#define HAMMER2_SET_COUNT 8 /* direct entries & associativity */
+#define HAMMER2_SET_COUNT 8 /* direct entries */
#define HAMMER2_SET_RADIX 3
#define HAMMER2_EMBEDDED_BYTES 512
#define HAMMER2_EMBEDDED_RADIX 9
@@ -153,8 +162,51 @@
* A HAMMER2 filesystem is always sized in multiples of 8MB.
*
* A 4MB segment is reserved at the beginning of each 2GB zone. This segment
- * contains the volume header, the free block table, and possibly other
- * information in the future. 4MB = 64 x 64K blocks.
+ * contains the volume header (or backup volume header), the free block
+ * table, and possibly other information in the future.
+ *
+ * 4MB = 64 x 64K blocks. Each 4MB segment is broken down as follows:
+ *
+ * +-----------------------+
+ * | Volume Hdr | block 0 volume header & alternates
+ * +-----------------------+ (first four zones only)
+ * | (A) FreeBlk layer0 | block 1 free block table
+ * | (A) FreeBlk layer1 |
+ * | (A) FreeBlk layer2 |
+ * | (A) FreeBlk layer3 |
+ * | (A) FreeBlk layer4[8] | (note: 8x64K -> 128x4K)
+ * +-----------------------+
+ * | (B) FreeBlk layer0 | block 13 free block table
+ * | (B) FreeBlk layer1 |
+ * | (B) FreeBlk layer2 |
+ * | (B) FreeBlk layer3 |
+ * | (B) FreeBlk layer4[8] |
+ * +-----------------------+
+ * | (C) FreeBlk layer0 | block 25 free block table
+ * | (C) FreeBlk layer1 |
+ * | (C) FreeBlk layer2 |
+ * | (C) FreeBlk layer3 |
+ * | (C) FreeBlk layer4[8] |
+ * +-----------------------+
+ * | (D) FreeBlk layer0 | block 37 free block table
+ * | (D) FreeBlk layer1 |
+ * | (D) FreeBlk layer2 |
+ * | (D) FreeBlk layer3 |
+ * | (D) FreeBlk layer4[8] |
+ * +-----------------------+
+ * | | block 49...63
+ * | reserved |
+ * | |
+ * +-----------------------+
+ *
+ * The first few 2GB zones contain volume headers and volume header backups.
+ * After that the volume header block# is reserved. The first 2GB zone
+ * contains all four FreeBlk layers, for example, but the layer1 FreeBlk
+ * is only needed once every 1TB. The free block topology rotates between
+ * several groups {A,B,C,D} in order to ensure that the free block table
+ * is clean upon reboot after a crash or disk failure.
+ *
+ * The Free block table has a resolution of 1KB
*/
#define HAMMER2_VOLUME_ALIGN (8 * 1024 * 1024)
#define HAMMER2_VOLUME_ALIGN64 ((hammer2_off_t)HAMMER2_VOLUME_ALIGN)
@@ -173,6 +225,52 @@
#define HAMMER2_ZONE_BLOCKS_SEG (HAMMER2_ZONE_SEG / HAMMER2_PBUFSIZE)
/*
+ * 64 x 64KB blocks are reserved at the base of each 2GB zone. These blocks
+ * are used to store the volume header or volume header backups, allocation
+ * tree, and other information in the future.
+ *
+ * All specified blocks are not necessarily used in all 2GB zones. However,
+ * dead areas are reserved and MUST NOT BE USED for other purposes.
+ *
+ * The freemap is arranged into four groups. Modifications rotate through
+ * the groups on a block by block basis (so all the blocks are not necessarily
+ * synchronized to the same group). Only three groups are actually necessary
+ * (stable, flushing, modifying).
+ *
+ * 64KB freemap indirect blocks are represented by layers 0, 1, 2, and 3.
+ * 4KB freemap leaf blocks each represent 16MB of storage so 128 x 4KB are
+ * needed per zone, which equates to 8 x 64KB layer4 blocks per zone.
+ */
+#define HAMMER2_ZONE_VOLHDR 0 /* volume header or backup */
+#define HAMMER2_ZONE_FREEMAP_A 1 /* freemap layer group A */
+#define HAMMER2_ZONE_FREEMAP_B 13 /* freemap layer group B */
+#define HAMMER2_ZONE_FREEMAP_C 25 /* freemap layer group C */
+#define HAMMER2_ZONE_FREEMAP_D 37 /* freemap layer group D */
+
+#define HAMMER2_ZONEFM_LAYER0 0 /* relative to FREEMAP_x */
+#define HAMMER2_ZONEFM_LAYER1 1
+#define HAMMER2_ZONEFM_LAYER2 2
+#define HAMMER2_ZONEFM_LAYER3 3
+#define HAMMER2_ZONEFM_LAYER4 4 /* 4-11 (8 64KB blocks) */
+
+#define HAMMER2_ZONE_BLOCK49 49 /* future */
+#define HAMMER2_ZONE_BLOCK50 50 /* future */
+#define HAMMER2_ZONE_BLOCK51 51 /* future */
+#define HAMMER2_ZONE_BLOCK52 52 /* future */
+#define HAMMER2_ZONE_BLOCK53 53 /* future */
+#define HAMMER2_ZONE_BLOCK54 54 /* future */
+#define HAMMER2_ZONE_BLOCK55 55 /* future */
+#define HAMMER2_ZONE_BLOCK56 56 /* future */
+#define HAMMER2_ZONE_BLOCK57 57 /* future */
+#define HAMMER2_ZONE_BLOCK58 58 /* future */
+#define HAMMER2_ZONE_BLOCK59 59 /* future */
+
+#define HAMMER2_ZONE_BLOCK60 60 /* future */
+#define HAMMER2_ZONE_BLOCK61 61 /* future */
+#define HAMMER2_ZONE_BLOCK62 62 /* future */
+#define HAMMER2_ZONE_BLOCK63 63 /* future */
+
+/*
* Two linear areas can be reserved after the initial 2MB segment in the base
* zone (the one starting at offset 0). These areas are NOT managed by the
* block allocator and do not fall under HAMMER2 crc checking rules based
@@ -215,9 +313,11 @@ typedef uint32_t hammer2_crc32_t;
*
* Indexes into physical buffers are always 64-byte aligned. The low 6 bits
* of the data offset field specifies how large the data chunk being pointed
- * to as a power of 2. This value typically ranges from HAMMER2_MIN_RADIX
- * to HAMMER2_MAX_RADIX (6-16). Larger values may be supported in the future
- * to support file extents.
+ * to as a power of 2. The theoretical minimum radix is thus 6 (The space
+ * needed in the low bits of the data offset field). However, the practical
+ * minimum allocation chunk size is 1KB (a radix of 10), so HAMMER2 sets
+ * HAMMER2_MIN_RADIX to 10. The maximum radix is currently 16 (64KB), but
+ * we fully intend to support larger extents in the future.
*/
#define HAMMER2_OFF_BAD ((hammer2_off_t)-1)
#define HAMMER2_OFF_MASK 0xFFFFFFFFFFFFFFC0ULL
@@ -259,6 +359,13 @@ typedef uint32_t hammer2_crc32_t;
* UNLESS one doesn't mind once-in-a-blue-moon data corruption (such as when
* farming web data). HAMMER2 has an unverified dedup feature for just this
* purpose.
+ *
+ * --
+ *
+ * NOTE: The range of keys represented by the blockref is (key) to
+ * ((key) + (1LL << keybits) - 1). HAMMER2 usually populates
+ * blocks bottom-up, inserting a new root when radix expansion
+ * is required.
*/
struct hammer2_blockref { /* MUST BE EXACTLY 64 BYTES */
uint8_t type; /* type of underlying item */
@@ -286,15 +393,41 @@ struct hammer2_blockref { /* MUST BE EXACTLY 64 BYTES */
struct {
char data[24];
} sha192;
+
+ /*
+ * Freemap hints are embedded in addition to the icrc32.
+ *
+ * biggest - largest possible allocation 2^N within sub-tree.
+ * typically initialized to 64 in freemap_blockref
+ * and to 54 in each blockref[] entry in the
+ * FREEMAP_ROOT indirect block.
+ *
+ * An allocation > 2^N is guaranteed to fail. An
+ * allocation <= 2^N MAY fail, and if it does the
+ * biggest hint will be adjusted downward.
+ *
+ * Used when allocating space.
+ */
+ struct {
+ uint32_t icrc32;
+ uint8_t biggest;
+ uint8_t reserved05;
+ uint8_t reserved06;
+ uint8_t reserved07;
+ uint64_t avail; /* total available bytes */
+ uint64_t unused; /* unused must be 0 */
+ } freemap;
} check;
};
typedef struct hammer2_blockref hammer2_blockref_t;
+#if 0
#define HAMMER2_BREF_SYNC1 0x01 /* modification synchronized */
#define HAMMER2_BREF_SYNC2 0x02 /* modification committed */
#define HAMMER2_BREF_DESYNCCHLD 0x04 /* desynchronize children */
#define HAMMER2_BREF_DELETED 0x80 /* indicates a deletion */
+#endif
#define HAMMER2_BLOCKREF_BYTES 64 /* blockref struct in bytes */
@@ -302,12 +435,26 @@ typedef struct hammer2_blockref hammer2_blockref_t;
#define HAMMER2_BREF_TYPE_INODE 1
#define HAMMER2_BREF_TYPE_INDIRECT 2
#define HAMMER2_BREF_TYPE_DATA 3
+#define HAMMER2_BREF_TYPE_FREEMAP_ROOT 4
+#define HAMMER2_BREF_TYPE_FREEMAP_NODE 5
+#define HAMMER2_BREF_TYPE_FREEMAP_LEAF 6
#define HAMMER2_BREF_TYPE_VOLUME 255 /* pseudo-type */
-#define HAMMER2_ENC_COMPMETHOD(n) (n)
-#define HAMMER2_ENC_CHECKMETHOD(n) ((n) << 4)
-#define HAMMER2_DEC_COMPMETHOD(n) ((n) & 15)
-#define HAMMER2_DEC_CHECKMETHOD(n) (((n) >> 4) & 15)
+#define HAMMER2_ENC_CHECK(n) ((n) << 4)
+#define HAMMER2_DEC_CHECK(n) (((n) >> 4) & 15)
+
+#define HAMMER2_CHECK_NONE 0
+#define HAMMER2_CHECK_ISCSI32 1
+#define HAMMER2_CHECK_CRC64 2
+#define HAMMER2_CHECK_SHA192 3
+#define HAMMER2_CHECK_FREEMAP 4
+
+#define HAMMER2_ENC_COMP(n) (n)
+#define HAMMER2_DEC_COMP(n) ((n) & 15)
+
+#define HAMMER2_COMP_NONE 0
+#define HAMMER2_COMP_AUTOZERO 1
+
/*
* HAMMER2 block references are collected into sets of 8 blockrefs. These
@@ -330,6 +477,9 @@ typedef struct hammer2_blockref hammer2_blockref_t;
* until the set actually becomes full (that is, the entries in the set can
* shortcut the indirect blocks when the set is not full). Depending on how
* things are filled multiple indirect blocks will eventually be created.
+ *
+ * Indirect blocks are typically 4KB (64 entres) or 64KB (1024 entries) and
+ * are also treated as fully set-associative.
*/
struct hammer2_blockset {
hammer2_blockref_t blockref[HAMMER2_SET_COUNT];
@@ -504,12 +654,6 @@ typedef struct hammer2_inode_data hammer2_inode_data_t;
#define HAMMER2_COPYID_NONE 0
#define HAMMER2_COPYID_LOCAL ((uint8_t)-1)
-#define HAMMER2_COMP_NONE 0
-#define HAMMER2_COMP_AUTOZERO 1
-
-#define HAMMER2_CHECK_NONE 0
-#define HAMMER2_CHECK_ICRC 1
-
/*
* PEER types identify connections and help cluster controller filter
* out unwanted SPANs.
@@ -536,75 +680,113 @@ typedef struct hammer2_inode_data hammer2_inode_data_t;
#define HAMMER2_PFSTYPE_MAX DMSG_PFSTYPE_MAX
/*
- * The allocref structure represents the allocation table. One 64K block
- * is broken down into 4096 x 16 byte entries. Each indirect block chops
- * 11 bits off the 64-bit storage space, with leaf entries representing
- * 64KB blocks. So: (12, 12, 12, 12, 16) = 64 bit storage space.
- *
- * Each 64K freemap block breaks the 4096 entries into a 64x64 tree with
- * big_hint1 representing the top level every 64th entry and big_hint2
- * representing the lower level in each entry. These fields specify the
- * largest contiguous radix (1-63) available for allocation in the related
- * sub-tree. The largest contiguous radix available for the entire block
- * is saved in the parent (for the root this will be alloc_blockref in the
- * volume header). The hints may be larger than actual and will be corrected
- * on the fly but must not be smaller. The allocator uses the hints to
- * very quickly locate nearby blocks of the desired size.
- *
- * In indirect blocks the 64-bit free[_or_mask] field stores the total free
- * space for each of the 4096 sub-nodes in bytes. The total free space
- * represented by the indirect block is stored in its parent.
- *
- * Each leaf element represents a 64K block. A bitmap replaces the free space
- * count, giving us a 1KB allocation resolution. A micro-allocation append
- * offset replaces the icrc field. The micro-allocation feature is not
- * currently implemented and the field will be set to 65536.
- *
- * The allocation map uses reserved blocks so no data block reference is
- * required, only a bit in the flags field to specify which of two possible
- * reserved blocks to use. This allows the allocation map to be flushed to
- * disk with minimal synchronization.
+ * Allocation Table
+ *
+ * In HAMMER2 the allocation table hangs off of the volume header and
+ * utilizes somewhat customized hammer2_blockref based indirect blocks
+ * until hitting the leaf bitmap. BREF_TYPE_FREEMAP_ROOT and
+ * BREF_TYPE_FREEMAP_NODE represent the indirect blocks but are formatted
+ * the same as BREF_TYPE_INDIRECT except for the (biggest) and (avail)
+ * fields which use some of the check union space. Thus a special CHECK
+ * id (CHECK_FREEMAP instead of CHECK_ISCSI32) is also specified for these
+ * babies.
+ *
+ * newfs_hammer2 builds the FREEMAP_ROOT block and assigns a radix of
+ * 34, 44, 54, or 64 depending on whether the freemap is to be fitted
+ * to the storage or is to maximized for (possibly) sparse storage.
+ * Other keybits specifications for FREEMAP_ROOT are illegal. Even fitted
+ * storage is required to specify at least a keybits value of 34.
+ *
+ * Total possible representation is 2^64 (16 Exabytes).
+ * 10: 1024 entries / 64KB 16EB (16PB per entry) layer0
+ * 10: 1024 entries / 64KB 16PB (16TB per entry) layer1
+ * 10: 1024 entries / 64KB 16TB (16GB per entry) layer2
+ * 10: 1024 entries / 64KB 16GB (16MB per entry) layer3
+ * 24: 16384 x 1KB allocgran / 4KB 16MB layer4
+ *
+ * To make the radix come out to exactly 64 the leaf bitmaps are arranged
+ * into 4KB buffers, with each buffer representing a freemap for 16MB worth
+ * of storage using a 1KB allocation granularity. The leaf bitmaps are
+ * structures and not just a plain bitmap, hence the extra space needed to
+ * represent 16384 x 1KB blocks.
+ *
+ * The reserved area at the beginning of each 2GB zone is marked as being
+ * allocated on-the-fly and does not have to be pre-set in the freemap,
+ * which is just as well as that would require newfs_hammer2 to do a lot
+ * of writing otherwise.
+ *
+ * Indirect blocks are usually created with a semi-dynamic radix but in the
+ * case of freemap-related indirect blocks, the blocks use a static radix
+ * tree with associations to specific reserved blocks.
*/
-struct hammer2_allocref {
- uint32_t icrc_or_app; /* node: icrc, leaf: append offset */
- uint16_t flags;
- uint8_t big_hint1; /* upper level hint */
- uint8_t big_hint2; /* lower level hint */
- uint64_t free_or_mask; /* node: free bytes, leaf: bitmask */
-};
-
-typedef struct hammer2_allocref hammer2_allocref_t;
/*
- * WARNING - allocref size x entries must equate to the hammer buffer size,
- * and 12 bits per recursion is assumed by the allocator.
+ * 4KB -> hammer2_freemap_elm[256]
+ *
+ * bitmap - 64 bits x 1KB representing 64KB. A '1' bit represents
+ * an allocated block.
+ *
+ * generation - Incremented upon any allocation. Can't increment more
+ * than +64 per background freeing pass due to there being
+ * only 64 bits.
*
- * ALTA-D Since no data_offset is specified flags are needed to select
- * which sub-block to recurse down into for root & internal nodes.
- * (only ALTA and ALTB is currently supported).
+ * biggest0 - biggest hint (radix) for freemap_elm. Represents up to
+ * 64KB (radix 16).
*
- * LEAF Terminal entry, always set for leafs. May be used to support
- * 4MB extent allocations and early termination in the future.
- * (not required to shortcut allocation scans as the big_hint1/2
- * fields are used for this).
+ * biggest1 - biggest hint (radix) for aligned groups of 16 elements,
+ * stored in elm[0], elm[16], etc. Represents up to 1MB.
+ * (radix 20)
+ *
+ * biggest2 - biggest hint (radix) for aligned groups of 256 elements
+ * (i.e. the whole array, only used by elm[0]).
+ * Represents up to 16MB (radix 24).
+ *
+ * The hinting is used as part of the allocation mechanism to reduce scan
+ * time, which is particularly important as a filesystem approaches full.
+ * Fill ratios are handled at the indirect block level (in the blockrefs) and
+ * not here.
*/
-#define HAMMER2_ALLOCREF_BYTES 16 /* structure size */
-#define HAMMER2_ALLOCREF_ENTRIES 4096 /* entries */
-#define HAMMER2_ALLOCREF_RADIX 12 /* log2(entries) */
+struct hammer2_freemap_elm {
+ uint64_t bitmap;
+ uint8_t generation;
+ uint8_t biggest0;
+ uint8_t biggest1;
+ uint8_t biggest2;
+ uint32_t reserved0C;
+};
-#if (HAMMER2_ALLOCREF_BYTES * HAMMER2_ALLOCREF_ENTRIES) != HAMMER2_PBUFSIZE
-#error "allocref parameters do not fit in hammer buffer"
-#endif
-#if (1 << HAMMER2_ALLOCREF_RADIX) != HAMMER2_ALLOCREF_ENTRIES
-#error "allocref parameters are inconsistent"
-#endif
+typedef struct hammer2_freemap_elm hammer2_freemap_elm_t;
-#define HAMMER2_ALLOCREF_ALTMASK 0x0003 /* select block for recurse */
-#define HAMMER2_ALLOCREF_ALTA 0x0000
-#define HAMMER2_ALLOCREF_ALTB 0x0001
-#define HAMMER2_ALLOCREF_ALTC 0x0002 /* unsupported */
-#define HAMMER2_ALLOCREF_ALTD 0x0003 /* unsupported */
-#define HAMMER2_ALLOCREF_LEAF 0x0004
+#define HAMMER2_FREEMAP_LEAF_BYTES 4096
+#define HAMMER2_FREEMAP_LEAF_ENTRIES (HAMMER2_FREEMAP_LEAF_BYTES / \
+ sizeof(hammer2_freemap_elm_t))
+#define HAMMER2_FREEMAP_LEAF_RADIX 24
+#define HAMMER2_FREEMAP_NODE_RADIX 10
+#define HAMMER2_FREEMAP_ELM_RADIX 5 /* 2^5 == 32 bits */
+
+#define HAMMER2_BIGF_KILLED 0x80
+
+/*
+ * Flags (8 bits) - blockref, for freemap only
+ *
+ * Note that the minimum chunk size is 1KB so we could theoretically have
+ * 10 bits here, but we might have some future extension that allows a
+ * chunk size down to 256 bytes and if so we will need bits 8 and 9.
+ */
+#define HAMMER2_AVF_SELMASK 0x03 /* select group */
+#define HAMMER2_AVF_ALL_ALLOC 0x04 /* indicate all allocated */
+#define HAMMER2_AVF_ALL_FREE 0x08 /* indicate all free */
+#define HAMMER2_AVF_RESERVED10 0x10
+#define HAMMER2_AVF_RESERVED20 0x20
+#define HAMMER2_AVF_RESERVED40 0x40
+#define HAMMER2_AVF_RESERVED80 0x80
+#define HAMMER2_AVF_AVMASK32 ((uint32_t)0xFFFFFF00LU)
+#define HAMMER2_AVF_AVMASK64 ((uint64_t)0xFFFFFFFFFFFFFF00LLU)
+
+#define HAMMER2_AV_SELECT_A 0x00
+#define HAMMER2_AV_SELECT_B 0x01
+#define HAMMER2_AV_SELECT_C 0x02
+#define HAMMER2_AV_SELECT_D 0x03
/*
* The volume header eats a 64K block. There is currently an issue where
@@ -681,8 +863,8 @@ struct hammer2_volume_data {
* allocator_size is precalculated at newfs time and does not include
* reserved blocks, boot, or redo areas.
*
- * Initial non-reserved-area allocations do not use the allocation
- * map but instead adjust alloc_iterator. Dynamic allocations take
+ * Initial non-reserved-area allocations do not use the freemap
+ * but instead adjust alloc_iterator. Dynamic allocations take
* over starting at (allocator_beg). This makes newfs_hammer2's
* job a lot easier and can also serve as a testing jig.
*/
@@ -691,7 +873,7 @@ struct hammer2_volume_data {
hammer2_off_t allocator_beg; /* 0070 Initial allocations */
hammer2_tid_t mirror_tid; /* 0078 best committed tid */
hammer2_tid_t alloc_tid; /* 0080 Alloctable modify tid */
- hammer2_blockref_t alloc_blockref; /* 0088-00C7 */
+ hammer2_blockref_t freemap_blockref; /* 0088-00C7 */
/*
* Copyids are allocated dynamically from the copyexists bitmap.
View
2  sys/vfs/hammer2/hammer2_flush.c
@@ -691,6 +691,8 @@ hammer2_chain_flush_pass1(hammer2_mount_t *hmp, hammer2_chain_t *chain,
bref = &chain->bref;
KKASSERT((bref->data_off & HAMMER2_OFF_MASK) != 0);
+ KKASSERT(HAMMER2_DEC_CHECK(chain->bref.methods) ==
+ HAMMER2_CHECK_ISCSI32);
if (chain->bp == NULL) {
/*
View
2  sys/vfs/hammer2/hammer2_freemap.c
@@ -80,7 +80,7 @@ hammer2_freemap_alloc(hammer2_mount_t *hmp, int type, size_t bytes)
/*
* Figure out the base 2 radix of the allocation (rounded up)
*/
- radix = hammer2_bytes_to_radix(bytes);
+ radix = hammer2_allocsize(bytes);
bytes = 1 << radix;
if (radix <= HAMMER2_MAX_RADIX)
View
10 sys/vfs/hammer2/hammer2_subr.c
@@ -345,10 +345,11 @@ hammer2_dirhash(const unsigned char *name, size_t len)
* Return the power-of-2 radix greater or equal to
* the specified number of bytes.
*
- * Always returns at least HAMMER2_MIN_RADIX (2^6).
+ * Always returns at least the minimum media allocation
+ * size radix, HAMMER2_MIN_RADIX (10), which is 1KB.
*/
int
-hammer2_bytes_to_radix(size_t bytes)
+hammer2_allocsize(size_t bytes)
{
int radix;
@@ -356,6 +357,8 @@ hammer2_bytes_to_radix(size_t bytes)
bytes = HAMMER2_MIN_ALLOC;
if (bytes == HAMMER2_PBUFSIZE)
radix = HAMMER2_PBUFRADIX;
+ else if (bytes >= 16384)
+ radix = 14;
else if (bytes >= 1024)
radix = 10;
else
@@ -376,8 +379,7 @@ hammer2_calc_logical(hammer2_inode_t *ip, hammer2_off_t uoff,
*leofp = ip->ip_data.size & ~HAMMER2_PBUFMASK64;
KKASSERT(*lbasep <= *leofp);
if (*lbasep == *leofp /*&& *leofp < 1024 * 1024*/) {
- radix = hammer2_bytes_to_radix(
- (size_t)(ip->ip_data.size - *leofp));
+ radix = hammer2_allocsize((size_t)(ip->ip_data.size - *leofp));
if (radix < HAMMER2_MINALLOCRADIX)
radix = HAMMER2_MINALLOCRADIX;
*leofp += 1U << radix;
View
4 sys/vfs/hammer2/hammer2_vfsops.c
@@ -66,10 +66,12 @@ long hammer2_iod_indr_read;
long hammer2_iod_file_write;
long hammer2_iod_meta_write;
long hammer2_iod_indr_write;
+long hammer2_iod_fmap_write;
long hammer2_iod_volu_write;
long hammer2_ioa_file_read;
long hammer2_ioa_meta_read;
long hammer2_ioa_indr_read;
+long hammer2_ioa_fmap_write;
long hammer2_ioa_file_write;
long hammer2_ioa_meta_write;
long hammer2_ioa_indr_write;
@@ -173,8 +175,6 @@ hammer2_vfs_init(struct vfsconf *conf)
error = EINVAL;
if (HAMMER2_INODE_BYTES != sizeof(struct hammer2_inode_data))
error = EINVAL;
- if (HAMMER2_ALLOCREF_BYTES != sizeof(struct hammer2_allocref))
- error = EINVAL;
if (HAMMER2_VOLUME_BYTES != sizeof(struct hammer2_volume_data))
error = EINVAL;
View
6 sys/vfs/hammer2/hammer2_vnops.c
@@ -1076,7 +1076,7 @@ hammer2_truncate_file(hammer2_inode_t *ip, hammer2_key_t nsize)
switch(chain->bref.type) {
case HAMMER2_BREF_TYPE_DATA:
hammer2_chain_resize(ip, chain,
- hammer2_bytes_to_radix(nblksize),
+ hammer2_allocsize(nblksize),
HAMMER2_MODIFY_OPTDATA);
bzero(bp->b_data + loff, nblksize - loff);
bp->b_bio2.bio_offset = chain->bref.data_off &
@@ -1119,7 +1119,7 @@ hammer2_truncate_file(hammer2_inode_t *ip, hammer2_key_t nsize)
switch(chain->bref.type) {
case HAMMER2_BREF_TYPE_DATA:
hammer2_chain_resize(ip, chain,
- hammer2_bytes_to_radix(nblksize),
+ hammer2_allocsize(nblksize),
0);
hammer2_chain_modify(hmp, chain, 0);
bzero(chain->data->buf + loff, nblksize - loff);
@@ -1284,7 +1284,7 @@ hammer2_extend_file(hammer2_inode_t *ip, hammer2_key_t nsize)
error = hammer2_chain_lock(hmp, parent, HAMMER2_RESOLVE_ALWAYS);
KKASSERT(error == 0);
- nradix = hammer2_bytes_to_radix(nblksize);
+ nradix = hammer2_allocsize(nblksize);
chain = hammer2_chain_lookup(hmp, &parent,
obase, obase,
Please sign in to comment.
Something went wrong with that request. Please try again.