diff --git a/uts/common/fs/zfs/dmu_objset.c b/uts/common/fs/zfs/dmu_objset.c index efad81dd2cdd..b6ae9680ca6e 100644 --- a/uts/common/fs/zfs/dmu_objset.c +++ b/uts/common/fs/zfs/dmu_objset.c @@ -787,11 +787,17 @@ dmu_objset_create_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp, /* * Determine the number of levels necessary for the meta-dnode - * to contain DN_MAX_OBJECT dnodes. + * to contain DN_MAX_OBJECT dnodes. Note that in order to + * ensure that we do not overflow 64 bits, there has to be + * a nlevels that gives us a number of blocks > DN_MAX_OBJECT + * but < 2^64. Therefore, + * (mdn->dn_indblkshift - SPA_BLKPTRSHIFT) (10) must be + * less than (64 - log2(DN_MAX_OBJECT)) (16). */ - while ((uint64_t)mdn->dn_nblkptr << (mdn->dn_datablkshift + + while ((uint64_t)mdn->dn_nblkptr << + (mdn->dn_datablkshift - DNODE_SHIFT + (levels - 1) * (mdn->dn_indblkshift - SPA_BLKPTRSHIFT)) < - DN_MAX_OBJECT * sizeof (dnode_phys_t)) + DN_MAX_OBJECT) levels++; mdn->dn_next_nlevels[tx->tx_txg & TXG_MASK] = diff --git a/uts/common/fs/zfs/spa_misc.c b/uts/common/fs/zfs/spa_misc.c index 699b15cc58da..a674eea6b047 100644 --- a/uts/common/fs/zfs/spa_misc.c +++ b/uts/common/fs/zfs/spa_misc.c @@ -341,9 +341,14 @@ int spa_asize_inflation = 24; * it is possible to run the pool completely out of space, causing it to * be permanently read-only. * + * Note that on very small pools, the slop space will be larger than + * 3.2%, in an effort to have it be at least spa_min_slop (128MB), + * but we never allow it to be more than half the pool size. + * * See also the comments in zfs_space_check_t. */ int spa_slop_shift = 5; +uint64_t spa_min_slop = 128 * 1024 * 1024; /* * ========================================================================== @@ -1637,14 +1642,16 @@ spa_get_asize(spa_t *spa, uint64_t lsize) /* * Return the amount of slop space in bytes. It is 1/32 of the pool (3.2%), - * or at least 32MB. + * or at least 128MB, unless that would cause it to be more than half the + * pool size. * * See the comment above spa_slop_shift for details. */ uint64_t -spa_get_slop_space(spa_t *spa) { +spa_get_slop_space(spa_t *spa) +{ uint64_t space = spa_get_dspace(spa); - return (MAX(space >> spa_slop_shift, SPA_MINDEVSIZE >> 1)); + return (MAX(space >> spa_slop_shift, MIN(space >> 1, spa_min_slop))); } uint64_t diff --git a/uts/common/fs/zfs/sys/dnode.h b/uts/common/fs/zfs/sys/dnode.h index dfa3e576c58e..98780b2566af 100644 --- a/uts/common/fs/zfs/sys/dnode.h +++ b/uts/common/fs/zfs/sys/dnode.h @@ -58,7 +58,7 @@ extern "C" { */ #define DNODE_SHIFT 9 /* 512 bytes */ #define DN_MIN_INDBLKSHIFT 12 /* 4k */ -#define DN_MAX_INDBLKSHIFT 14 /* 16k */ +#define DN_MAX_INDBLKSHIFT 17 /* 128k */ #define DNODE_BLOCK_SHIFT 14 /* 16k */ #define DNODE_CORE_SIZE 64 /* 64 bytes for dnode sans blkptrs */ #define DN_MAX_OBJECT_SHIFT 48 /* 256 trillion (zfs_fid_t limit) */ @@ -88,6 +88,11 @@ extern "C" { #define DNODES_PER_BLOCK_SHIFT (DNODE_BLOCK_SHIFT - DNODE_SHIFT) #define DNODES_PER_BLOCK (1ULL << DNODES_PER_BLOCK_SHIFT) + +/* + * This is inaccurate if the indblkshift of the particular object is not the + * max. But it's only used by userland to calculate the zvol reservation. + */ #define DNODES_PER_LEVEL_SHIFT (DN_MAX_INDBLKSHIFT - SPA_BLKPTRSHIFT) #define DNODES_PER_LEVEL (1ULL << DNODES_PER_LEVEL_SHIFT) diff --git a/uts/common/sys/fs/zfs.h b/uts/common/sys/fs/zfs.h index ebae8beb1da5..6282712b31db 100644 --- a/uts/common/sys/fs/zfs.h +++ b/uts/common/sys/fs/zfs.h @@ -600,6 +600,8 @@ typedef struct zpool_rewind_policy { /* * This is needed in userland to report the minimum necessary device size. + * + * Note that the zfs test suite uses 64MB vdevs. */ #define SPA_MINDEVSIZE (64ULL << 20)