Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F174969630
D60270.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
14 KB
Referenced Files
None
Subscribers
None
D60270.id.diff
View Options
diff --git a/tools/boot/boot-test.sh b/tools/boot/boot-test.sh
--- a/tools/boot/boot-test.sh
+++ b/tools/boot/boot-test.sh
@@ -505,10 +505,13 @@
# Create a ZFS image with a specific loader variant via mtree overlay
make_one_zfs() {
variant=$1
- img=${IMGDIR}/bootable-zfs-${variant}.img
+ image_variant=${2:-${variant}}
+ zfs_options=$3
+ symlink_efi_loader=$4
+ img=${IMGDIR}/bootable-zfs-${image_variant}.img
mt=$(mktemp ${OUTDIR}/zfs-mtree.XXXXXX)
- echo " Creating ZFS image with loader_${variant}..."
+ echo " Creating ZFS image ${image_variant} with loader_${variant}..."
> ${mt}
# BIOS: /boot/loader -> loader_<variant>
if [ -n "$(param bios_loaders)" ]; then
@@ -518,10 +521,15 @@
# tree (no per-variant overlay needed).
# EFI: /boot/loader.efi -> loader_<variant>.efi (needed for boot1.efi chainload)
if has efi; then
- echo "./boot/loader.efi type=file mode=0755 contents=${DESTDIR}/boot/loader_${variant}.efi" >> ${mt}
+ if [ "${symlink_efi_loader}" = yes ]; then
+ echo "./boot/loader.efi type=link link=loader_${variant}.efi" >> ${mt}
+ else
+ echo "./boot/loader.efi type=file mode=0755 contents=${DESTDIR}/boot/loader_${variant}.efi" >> ${mt}
+ fi
fi
makefs -t zfs -s 100m \
-o poolname=ztestroot -o bootfs=ztestroot -o rootpath=/ \
+ ${zfs_options} \
${img} ${mt} ${DESTDIR} >> ${LOGDIR}/imagebuild.log 2>&1
rm -f ${mt}
}
@@ -768,6 +776,10 @@
else
make_one_zfs lua
fi
+ # Keep these separate so failures distinguish dnode parsing from SA
+ # registry/layout parsing. Both use a symlink for the stage-3 loader.
+ make_one_zfs lua large-dnode "-o dnodesize=16384" yes
+ make_one_zfs lua alt-sa-layout "-o alt-sa-layout" yes
fi
# ESP images (if EFI is supported)
@@ -865,6 +877,22 @@
register_test ${name} $(qemu_efi ${img})
done
done
+
+ case " $(param efi_loaders) " in
+ *" boot1 "*)
+ if has zfs; then
+ name="efi-gpt-zfs-boot1-large-dnode"
+ img=${IMGDIR}/${name}.img
+
+ mkimg -s gpt \
+ -p efi:=${IMGDIR}/boot1.esp \
+ -p freebsd-zfs:=${IMGDIR}/bootable-zfs-large-dnode.img \
+ -o ${img} >> ${LOGDIR}/imagebuild.log 2>&1
+
+ register_test ${name} $(qemu_efi ${img})
+ fi
+ ;;
+ esac
}
# Build the A/B disk and register its test. Layout mirrors an A/B upgrade
@@ -936,6 +964,21 @@
register_test ${name} $(qemu_bios ${img})
fi
done
+
+ if has zfs; then
+ for feature in large-dnode alt-sa-layout; do
+ name="bios-gpt-zfs-${feature}"
+ img=${IMGDIR}/${name}.img
+ zfs=${IMGDIR}/bootable-zfs-${feature}.img
+
+ mkimg -s gpt -b ${DESTDIR}/boot/pmbr \
+ -p freebsd-boot:=${DESTDIR}/boot/gptzfsboot \
+ -p freebsd-zfs:=${zfs} \
+ -o ${img} >> ${LOGDIR}/imagebuild.log 2>&1
+
+ register_test ${name} $(qemu_bios ${img})
+ done
+ fi
}
assemble_bios_mbr() {
diff --git a/usr.sbin/makefs/makefs.8 b/usr.sbin/makefs/makefs.8
--- a/usr.sbin/makefs/makefs.8
+++ b/usr.sbin/makefs/makefs.8
@@ -535,11 +535,20 @@
The base-2 logarithm of the minimum block size.
Typical values are 9 (512B blocks) and 12 (4KB blocks).
The default value is 12.
+.It Cm alt-sa-layout
+Use an alternate ordering of ZPL system attributes.
+This option is intended for testing consumers of system attribute layouts.
.It Cm bootfs
The name of the bootable dataset for the pool.
Specifying this option causes the
.Ql bootfs
property to be set in the created pool.
+.It Cm dnodesize
+The size of ZPL dnodes in bytes.
+The value must be a power of two between 512 and 16384.
+The default value is 512.
+The ZPL master node remains 512 bytes because its fixed object number does not
+permit a 16384-byte dnode without crossing a dnode block boundary.
.It Cm mssize
The size of metaslabs in the created pool.
By default,
diff --git a/usr.sbin/makefs/zfs.c b/usr.sbin/makefs/zfs.c
--- a/usr.sbin/makefs/zfs.c
+++ b/usr.sbin/makefs/zfs.c
@@ -98,6 +98,10 @@
MINBLOCKSHIFT, MAXBLOCKSHIFT, "ZFS pool ashift" },
{ '\0', "verify-txgs", &zfs->verify_txgs, OPT_BOOL,
0, 0, "Make OpenZFS verify data upon import" },
+ { '\0', "dnodesize", &zfs->dnodesize, OPT_INT32,
+ DNODE_MIN_SIZE, DNODE_MAX_SIZE, "ZPL dnode size" },
+ { '\0', "alt-sa-layout", &zfs->alt_sa_layout, OPT_BOOL,
+ 0, 0, "Use an alternate ZPL SA layout" },
{ '\0', "nowarn", &zfs->nowarn, OPT_BOOL,
0, 0, "Provided for backwards compatibility, ignored" },
{ .name = NULL }
@@ -216,6 +220,11 @@
zfs = fsopts->fs_specific;
+ if (zfs->dnodesize == 0)
+ zfs->dnodesize = DNODE_MIN_SIZE;
+ if (!powerof2(zfs->dnodesize))
+ errx(1, "dnodesize must be a power of 2");
+
if (fsopts->offset != 0)
errx(1, "unhandled offset option");
if (fsopts->maxsize == 0)
@@ -441,20 +450,40 @@
static void
pool_init_objdir_feature_maps(zfs_opt_t *zfs, zfs_zap_t *objdir)
{
- dnode_phys_t *dnode;
+ dnode_phys_t *dnode, *featuredesc, *featureswrite;
uint64_t dnid;
dnode = objset_dnode_alloc(zfs->mos, DMU_OTN_ZAP_METADATA, &dnid);
zap_add_uint64(objdir, DMU_POOL_FEATURES_FOR_READ, dnid);
zap_write(zfs, zap_alloc(zfs->mos, dnode));
- dnode = objset_dnode_alloc(zfs->mos, DMU_OTN_ZAP_METADATA, &dnid);
+ featureswrite = objset_dnode_alloc(zfs->mos, DMU_OTN_ZAP_METADATA,
+ &dnid);
zap_add_uint64(objdir, DMU_POOL_FEATURES_FOR_WRITE, dnid);
- zap_write(zfs, zap_alloc(zfs->mos, dnode));
+ zfs->features_for_write = zap_alloc(zfs->mos, featureswrite);
- dnode = objset_dnode_alloc(zfs->mos, DMU_OTN_ZAP_METADATA, &dnid);
+ featuredesc = objset_dnode_alloc(zfs->mos, DMU_OTN_ZAP_METADATA,
+ &dnid);
zap_add_uint64(objdir, DMU_POOL_FEATURE_DESCRIPTIONS, dnid);
- zap_write(zfs, zap_alloc(zfs->mos, dnode));
+ zfs->feature_descriptions = zap_alloc(zfs->mos, featuredesc);
+}
+
+static void
+pool_feature_maps_write(zfs_opt_t *zfs)
+{
+ if (zfs->large_dnode_count != 0) {
+ zap_add_uint64(zfs->features_for_write,
+ ZFEATURE_EXTENSIBLE_DATASET, 0);
+ zap_add_uint64(zfs->features_for_write, ZFEATURE_LARGE_DNODE,
+ zfs->large_dnode_count);
+ zap_add_string(zfs->feature_descriptions,
+ ZFEATURE_EXTENSIBLE_DATASET,
+ "Enhanced dataset functionality, used by other features.");
+ zap_add_string(zfs->feature_descriptions, ZFEATURE_LARGE_DNODE,
+ "Variable on-disk size of dnodes.");
+ }
+ zap_write(zfs, zfs->features_for_write);
+ zap_write(zfs, zfs->feature_descriptions);
}
static void
@@ -646,6 +675,7 @@
{
zap_write(zfs, zfs->poolprops);
dsl_write(zfs);
+ pool_feature_maps_write(zfs);
objset_write(zfs, zfs->mos);
pool_labels_write(zfs);
}
diff --git a/usr.sbin/makefs/zfs/dsl.c b/usr.sbin/makefs/zfs/dsl.c
--- a/usr.sbin/makefs/zfs/dsl.c
+++ b/usr.sbin/makefs/zfs/dsl.c
@@ -42,6 +42,7 @@
zfs_objset_t *os; /* referenced objset, may be null */
dsl_dataset_phys_t *phys; /* on-disk representation */
uint64_t dsid; /* DSL dataset dnode */
+ dnode_phys_t *dnode;
struct zfs_dsl_dir *dir; /* containing parent */
} zfs_dsl_dataset_t;
@@ -562,6 +563,14 @@
headds->phys->ds_uncompressed_bytes = bytes;
headds->phys->ds_compressed_bytes = bytes;
+ if (zfs->dnodesize > DNODE_MIN_SIZE) {
+ zfs_zap_t *featurezap;
+
+ featurezap = zap_alloc(zfs->mos, headds->dnode);
+ zap_add_uint64(featurezap, ZFEATURE_LARGE_DNODE, 0);
+ zap_write(zfs, featurezap);
+ }
+
childbytes = 0;
STAILQ_FOREACH(cdir, &dir->children, next) {
/*
@@ -645,6 +654,7 @@
dnode = objset_dnode_bonus_alloc(zfs->mos, DMU_OT_DSL_DATASET,
DMU_OT_DSL_DATASET, sizeof(dsl_dataset_phys_t), &ds->dsid);
+ ds->dnode = dnode;
ds->phys = (dsl_dataset_phys_t *)DN_BONUS(dnode);
dnode = objset_dnode_bonus_alloc(zfs->mos, DMU_OT_DEADLIST,
diff --git a/usr.sbin/makefs/zfs/fs.c b/usr.sbin/makefs/zfs/fs.c
--- a/usr.sbin/makefs/zfs/fs.c
+++ b/usr.sbin/makefs/zfs/fs.c
@@ -89,7 +89,7 @@
} zpl_attr_t;
/*
- * This table must be kept in sync with zpl_attr_layout[] and zpl_attr_t.
+ * This table must be kept in sync with the layout tables and zpl_attr_t.
*/
static const zfs_sattr_t zpl_attrs[] = {
#define _ZPL_ATTR(n, s, b) { .name = #n, .id = n, .size = s, .bs = b }
@@ -119,9 +119,8 @@
};
/*
- * This layout matches that of a filesystem created using OpenZFS on FreeBSD.
- * It need not match in general, but FreeBSD's loader doesn't bother parsing the
- * layout and just hard-codes attribute offsets.
+ * This layout matches one generated by OpenZFS on FreeBSD. Layout numbers and
+ * attribute order are not fixed parts of the on-disk format.
*/
static const sa_attr_type_t zpl_attr_layout[] = {
ZPL_MODE,
@@ -141,6 +140,29 @@
ZPL_SYMLINK,
};
+/*
+ * A deliberately different, but equally valid, layout used to exercise SA
+ * consumers which discover attribute offsets from the registry and layout
+ * objects. As above, the symlink layout extends the default layout.
+ */
+static const sa_attr_type_t zpl_attr_layout_alt[] = {
+ ZPL_GEN,
+ ZPL_PARENT,
+ ZPL_UID,
+ ZPL_GID,
+ ZPL_MODE,
+ ZPL_SIZE,
+ ZPL_FLAGS,
+ ZPL_LINKS,
+ ZPL_ATIME,
+ ZPL_CTIME,
+ ZPL_MTIME,
+ ZPL_CRTIME,
+ ZPL_DACL_COUNT,
+ ZPL_DACL_ACES,
+ ZPL_SYMLINK,
+};
+
/*
* Keys for the ZPL attribute tables in the SA layout ZAP. The first two
* indices are reserved for legacy attribute encoding.
@@ -767,6 +789,8 @@
dnode_phys_t *saobj, *salobj, *sarobj;
uint64_t saobjid, salobjid, sarobjid;
uint16_t offset;
+ const sa_attr_type_t *layout;
+ size_t layoutcnt;
os = fs->os;
@@ -802,11 +826,18 @@
* ZPL_SYMLINK as its final attribute.
*/
salzap = zap_alloc(os, salobj);
- assert(zpl_attr_layout[nitems(zpl_attr_layout) - 1] == ZPL_SYMLINK);
+ if (zfs->alt_sa_layout) {
+ layout = zpl_attr_layout_alt;
+ layoutcnt = nitems(zpl_attr_layout_alt);
+ } else {
+ layout = zpl_attr_layout;
+ layoutcnt = nitems(zpl_attr_layout);
+ }
+ assert(layout[layoutcnt - 1] == ZPL_SYMLINK);
fs_add_zpl_attr_layout(salzap, SA_LAYOUT_INDEX_DEFAULT,
- zpl_attr_layout, nitems(zpl_attr_layout) - 1);
+ layout, layoutcnt - 1);
fs_add_zpl_attr_layout(salzap, SA_LAYOUT_INDEX_SYMLINK,
- zpl_attr_layout, nitems(zpl_attr_layout));
+ layout, layoutcnt);
zap_write(zfs, salzap);
sazap = zap_alloc(os, saobj);
@@ -829,13 +860,13 @@
for (size_t i = 0; i < fs->sacnt; i++)
fs->saoffs[i] = 0xffff;
offset = 0;
- for (size_t i = 0; i < nitems(zpl_attr_layout); i++) {
+ for (size_t i = 0; i < layoutcnt; i++) {
uint16_t size;
- assert(zpl_attr_layout[i] < fs->sacnt);
+ assert(layout[i] < fs->sacnt);
- fs->saoffs[zpl_attr_layout[i]] = offset;
- size = zpl_attrs[zpl_attr_layout[i]].size;
+ fs->saoffs[layout[i]] = offset;
+ size = zpl_attrs[layout[i]].size;
offset += size;
}
fs->satab = zpl_attrs;
diff --git a/usr.sbin/makefs/zfs/objset.c b/usr.sbin/makefs/zfs/objset.c
--- a/usr.sbin/makefs/zfs/objset.c
+++ b/usr.sbin/makefs/zfs/objset.c
@@ -57,6 +57,8 @@
/* dnode allocator. */
uint64_t dnodecount;
+ uint64_t objectcount;
+ unsigned int dnodeslots;
STAILQ_HEAD(, objset_dnode_chunk) dnodechunks;
} zfs_objset_t;
@@ -96,6 +98,10 @@
os->phys = ecalloc(1, os->osblksz);
os->phys->os_type = type;
+ os->dnodeslots = type == DMU_OST_ZFS ?
+ zfs->dnodesize / DNODE_MIN_SIZE : 1;
+ if (type == DMU_OST_ZFS && os->dnodeslots > DNODE_MIN_SLOTS)
+ zfs->large_dnode_count++;
dnode_init(&os->phys->os_meta_dnode, DMU_OT_DNODE, DMU_OT_NONE, 0);
os->phys->os_meta_dnode.dn_datablkszsec =
@@ -127,13 +133,19 @@
assert(chunk->nextfree <= DNODES_PER_CHUNK);
for (i = 0; i < chunk->nextfree; i += DNODES_PER_BLOCK) {
+ dnode_phys_t *dnode;
blkptr_t *bp;
uint64_t fill;
-
- if (chunk->nextfree - i < DNODES_PER_BLOCK)
- fill = DNODES_PER_BLOCK - (chunk->nextfree - i);
- else
- fill = 0;
+ unsigned int j;
+
+ fill = 0;
+ for (j = 0; j < DNODES_PER_BLOCK; j++) {
+ dnode = &chunk->buf[i + j];
+ if (dnode->dn_type != DMU_OT_NONE) {
+ fill++;
+ j += dnode->dn_extra_slots;
+ }
+ }
bp = dnode_cursor_next(zfs, c,
(total + i) * sizeof(dnode_phys_t));
vdev_pwrite_dnode_indir(zfs, &os->phys->os_meta_dnode,
@@ -152,7 +164,7 @@
* into the referencing DSL dataset or the uberblocks.
*/
vdev_pwrite_data(zfs, DMU_OT_OBJSET, ZIO_CHECKSUM_FLETCHER_4, 0,
- os->dnodecount - 1, os->phys, os->osblksz, os->osloc, &os->osbp);
+ os->objectcount, os->phys, os->osblksz, os->osloc, &os->osbp);
}
void
@@ -197,18 +209,38 @@
{
struct objset_dnode_chunk *chunk;
dnode_phys_t *dnode;
+ unsigned int nextblock, slots;
- assert(bonuslen <= DN_OLD_MAX_BONUSLEN);
assert(!STAILQ_EMPTY(&os->dnodechunks));
+ /*
+ * The ZPL master node has a fixed object number of one. A maximum-size
+ * dnode cannot begin in slot one without crossing a dnode block, so keep
+ * that bootstrap object at the legacy size. Dnode size is an object
+ * property, and OpenZFS pools may contain both sizes in one object set.
+ */
+ slots = os->dnodecount == MASTER_NODE_OBJ ? DNODE_MIN_SLOTS :
+ os->dnodeslots;
+ assert(slots >= DNODE_MIN_SLOTS && slots <= DNODE_MAX_SLOTS);
+ assert(bonuslen <= DN_SLOTS_TO_BONUSLEN(slots));
chunk = STAILQ_LAST(&os->dnodechunks, objset_dnode_chunk, next);
- if (chunk->nextfree == DNODES_PER_CHUNK) {
+ nextblock = roundup2(chunk->nextfree, DNODES_PER_BLOCK);
+ if (chunk->nextfree + slots > nextblock) {
+ os->dnodecount += nextblock - chunk->nextfree;
+ chunk->nextfree = nextblock;
+ }
+ if (chunk->nextfree + slots > DNODES_PER_CHUNK) {
+ os->dnodecount += DNODES_PER_CHUNK - chunk->nextfree;
chunk = ecalloc(1, sizeof(*chunk));
STAILQ_INSERT_TAIL(&os->dnodechunks, chunk, next);
}
- *idp = os->dnodecount++;
- dnode = &chunk->buf[chunk->nextfree++];
+ *idp = os->dnodecount;
+ os->dnodecount += slots;
+ os->objectcount++;
+ dnode = &chunk->buf[chunk->nextfree];
+ chunk->nextfree += slots;
dnode_init(dnode, type, bonustype, bonuslen);
+ dnode->dn_extra_slots = slots - 1;
dnode->dn_datablkszsec = os->osblksz >> MINBLOCKSHIFT;
return (dnode);
}
diff --git a/usr.sbin/makefs/zfs/zfs.h b/usr.sbin/makefs/zfs/zfs.h
--- a/usr.sbin/makefs/zfs/zfs.h
+++ b/usr.sbin/makefs/zfs/zfs.h
@@ -57,6 +57,9 @@
#define TXG 4
#define TXG_SIZE 4
+#define ZFEATURE_EXTENSIBLE_DATASET "com.delphix:extensible_dataset"
+#define ZFEATURE_LARGE_DNODE "org.zfsonlinux:large_dnode"
+
typedef struct zfs_dsl_dataset zfs_dsl_dataset_t;
typedef struct zfs_dsl_dir zfs_dsl_dir_t;
typedef struct zfs_objset zfs_objset_t;
@@ -85,6 +88,11 @@
uint64_t mssize; /* metaslab size */
STAILQ_HEAD(, dataset_desc) datasetdescs; /* non-root dataset descrs */
bool verify_txgs; /* verify data upon import */
+ int dnodesize; /* ZPL dnode size */
+ bool alt_sa_layout; /* use alternate SA layout */
+ uint64_t large_dnode_count;
+ zfs_zap_t *features_for_write;
+ zfs_zap_t *feature_descriptions;
/* Pool state. */
uint64_t poolguid; /* pool and root vdev GUID */
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Oct 8, 6:55 AM (16 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
40274924
Default Alt Text
D60270.id.diff (14 KB)
Attached To
Mode
D60270: makefs: support large dnodes and alternate SA layouts
Attached
Detach File
Event Timeline
Log In to Comment