Skip to content

build: fail the build when the OpenZFS patch series does not apply - #1495

Open
gburd wants to merge 1 commit into
cloudius-systems:masterfrom
gburd:pr/openzfs-patch-apply-errors
Open

gburd wants to merge 1 commit into
cloudius-systems:masterfrom
gburd:pr/openzfs-patch-apply-errors

Conversation

@gburd

@gburd gburd commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Summary

The OSv edits to the vendored OpenZFS tree are applied from a $(shell ...) near
the top of the Makefile:

$(shell if [ -d modules/open_zfs/openzfs/module ] && [ ! -f $(openzfs_patch_stamp) ]; then \
	git -C modules/open_zfs/openzfs apply --whitespace=nowarn $(addprefix ../patches/,...) 2>/dev/null \
	&& touch $(openzfs_patch_stamp); fi)

Two properties of that line compound into a silent wrong build.

git apply is not all-or-nothing across several patch files in one
invocation.
It can modify the files named by the earlier patches and then
reject a later one, leaving a partially patched tree.

A $(shell ...) exit status is invisible to make. git apply does report
the failure correctly with a non-zero status, and because of the && the stamp
file is correctly not written, so neither of those is the defect. The defect is
that nothing acts on the failure: make cannot see the status, and 2>/dev/null
discards the only other evidence. make proceeds to compile whatever the failed
apply left behind, which is an OpenZFS built with only some of the OSv platform
edits. It compiles cleanly and fails at run time, with nothing in the build
output pointing back at the cause.

Since the stamp is absent, the next make retries the apply against the
now-dirty tree, where it fails a second way ("patch does not apply"), so the tree
stays broken until the submodule is reset by hand.

The change

Keep git apply's diagnostic instead of discarding it, and require an explicit
sentinel from the recipe so that the apply and the stamp both have to succeed
before the build continues. Otherwise $(error ...) with the captured message
and the command that restores the submodule.

The apply is still skipped when the stamp exists and when the submodule is not
checked out. It is additionally skipped when the patch directory is empty, which
git apply would otherwise reject with "No valid patches in input" and which
would have turned into a spurious build failure.

Verified behaviour

Exercised against the real submodule at the pinned tag, and against a scratch
repository for the cases that need a deliberately broken patch:

case before after
single patch applies (master today) applies, stamped applies, stamped, unchanged
stamp already present skipped skipped, unchanged
submodule not checked out skipped skipped, unchanged
patch directory empty skipped skipped
a patch in the series fails build proceeds, exit 0 build stops, message shown
retry after a failed apply build proceeds again build stops, says how to restore

In the failing case before this change, make returned 0 and went on to the
compile step with the submodule left modified. After it:

Makefile:83: *** Failed to apply the OSv OpenZFS patches to
modules/open_zfs/openzfs: error: corrupt patch at ../patches/0031-....patch:45.
The submodule tree may be partially patched; restore it with
"git -C modules/open_zfs/openzfs checkout -- . && git -C modules/open_zfs/openzfs clean -fd"
before retrying.  Stop.

conf_zfs=bsd (the default) does not reach this code and is unaffected.

Motivation

master carries a single patch file today, so the partial-apply window is narrow
right now. The value of the guard is that it makes extending the series safe, and
that it converts a silent wrong build into a build failure that says what
happened. It is a small guard on a step whose failure is otherwise invisible.

One file.

The OSv edits to the vendored OpenZFS tree are applied by a $(shell ...) that
sends git apply stderr to /dev/null.  Two properties of that line compound
badly.

git apply is not all-or-nothing across several patch files in one invocation:
it can modify the files named by the earlier patches and then reject a later
one, leaving a partially patched tree.  git apply does report this correctly
with a non-zero status, and the "&& touch" means the stamp file is correctly
not written, but the exit status of a $(shell ...) is invisible to make, so
nothing stops the build, and with the diagnostic discarded nothing reports it
either.  make simply proceeds to compile whatever the failed apply left
behind: an OpenZFS built with only some of the OSv platform edits.  That
builds cleanly and then fails at run time, with nothing in the build output
pointing back at the cause.

Because the stamp is absent, the next make retries the apply against the
now-dirty tree, where it fails differently ("patch does not apply"), so the
tree stays broken until the submodule is reset by hand.

Keep the diagnostic on stderr and require an explicit sentinel from the
recipe, so the apply and the stamp both have to succeed before the build goes
on; otherwise fail with the message and how to restore the submodule.  The
apply is still skipped when the stamp exists, when the submodule is not
checked out, and now also when the patch directory is empty, which git apply
would otherwise reject.

master carries a single patch today, so the partial-apply window is narrow;
the point of the guard is that it makes extending the series safe and turns a
silent wrong build into a build failure that says what happened.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant