Raise zfs.resource validation errors as soon as a rule fails
## Problem
The zfs.resource create and set rules gathered every violation into a ValidationErrors collector and raised them together behind check() barriers, with the attachment delegates appending to the same collector. That diverged from the single-raise style master's zfs.resource used and carried a lot of verrors plumbing through every rule.
## Solution
- **Rules raise directly**: every create/set rule and shared reject_* helper, share_acl and the delegate validate_set hook drop their verrors param and raise a single ValidationError with the same attribute, message and errno the add used. Rule and loop order is unchanged, so callers now get the first error instead of all of them.
- **Collector removed**: create_impl and set lose the collector, the gate around the ancestor read and the check() barriers; the now dead except ValidationErrors arms around zr calls in pool.dataset and the S3 bucket dataset create are dropped.
- **Tests**: the unit and integration assertions on direct zr calls expect a single ValidationError, the headroom create test no longer sends a second violation, and the test asserting multiple violations are reported together is removed.
[TwoAddressInstruction] Drop physreg ranges after unfolding a load (#227538)
Since #225174 LiveIntervals is computed before TwoAddressInstructions.
When tryInstructionTransform() unfolds a load, e.g. OR64rm into
MOV64rm + OR64rr, it calls repairIntervalsInRange(). That function
only repairs virtual registers. If the regunit range of a physreg def
of the original instruction ($eflags here) was already cached, it
keeps a value defined at the slot of the erased instruction.
The machine verifier then reports "No instruction at VNInfo def index"
and later passes hit `LR.verify()` in LiveIntervals::HMEditor. This
broke the MSan bootstrap build of clang/lib/Sema/SemaAPINotes.cpp.
Drop the cached regunit ranges for the physregs of the unfolded
instruction so they are recomputed on demand. MachineBasicBlock.cpp
already does the same after repairIntervalsInRange().
Assisted-by: Gemini
WebAssembly: Take the exception model from the module flag
The WebAssembly EH passes chose whether and how to run from
MCAsmInfo::getExceptionHandlingType() and TargetOptions::ExceptionModel,
A module that asked for Wasm EH through the module flag alone would have
its invokes rewritten by LowerInvoke before WasmEHPrepare ran.
Schedule the passes unconditionally and read the module flag inside the
passes instead. Passes for other models can noop on the models they are
not intended for.
Co-authored-by: Claude Opus 5 <noreply at anthropic.com>
[LV][NFC] Fix erroneous debug message emitted during legality checks (#226162)
We erroneously state that we can vectorise the loop, since
LoopVectorizationLegality is no longer the oracle in matters of
legality. Many of the legality checks have been moved to vplan
construction, such as when attempting to vectorise some early exit
loops. It's very confusing to see debug output that says:
We can vectorize this loop.
Not vectorising the loop because of ...
I've updated the debug message to be more ambiguous.
After this patch I intend to follow up with another one to fix the
equally incorrect
LV: Vectorization is possible but not beneficial.
debug message, which assumes the reason for choosing a scalar VF is
because of the cost model. However, for some early exit loops we simply
failed to create any vector vplans!
[InferAddressSpaces] Insert fixup casts before cloned user during rewriting phase (#226987)
After reworking `operandWithNewAddressSpaceOrCreatePoison` in #225161 in
order to handle joins of different address spaces in the lattice to a
more specific address space, ensure that casts created during the fix-up
phase of poison uses are placed before the cloned user, as the latter
has already been inserted above the original instruction in
`cloneValueWithNewAddressSpace`.
TwoAddressInstructions: Use the per-operand early clobber flag for tied copies
The live interval update for the copy inserted for a tied operand ended
the new segment at getRegSlot(IsEarlyClobber), using a flag computed
once per instruction for any tied pairs. Use the flag
of the def actually being processed.
With an inline asm mixing "=&r" and "=r" outputs tied to the same input,
the copy for the plain def ended at the early clobber slot, leaving a
hole before its own def. That splits the live range into multiple
connected components and asserts in updatePressureDiffs.
Co-Authored-By: Claude Opus 5 <noreply at anthropic.com>
Use lfence to serialize rdtsc for VIA Nano and up, same as Linux do.
Unlike Linux I didn't add a 64-bit guard on assumption that it should work
the same way and the 64-bit version will likely be the preferred one by users.
planning to pull up to netbsd-11, netbsd-10.
Point the S3 bucket recovery code at zfs.resource.list_impl
## Problem
The bucket recovery code from master calls `zfs.resource.query_impl`, which this branch renamed to `list_impl`, so recovery would fail at runtime. A test comment also claimed destroying a bucket's dataset leaves its row behind, which is no longer true now that `zfs.resource.destroy` tears down attachments.
## Solution
Call `list_impl`, name `zfs.resource.list` in the `MOUNTED_FILESYSTEM` docstring and drop the stale test comment.
Assert the raw copies value in the pool.dataset.update shim test
## Problem
The test compared `copies` from `zfs.resource.list` against the integer 2, but `copies` is an index property in ZFS, so its parsed value comes back as the string label "2" and the assertion failed on every run.
## Solution
Assert the raw value "2", matching how the neighbouring dedup and compression tests check what ZFS stored.
Refuse volsize changes on read-only and locked volumes in zfs.resource.set
## Problem
ZFS applies each property in a request on its own, and it refuses a `volsize` change on a read-only or locked volume while still writing the rest of the request. When a thick volume was grown through `zfs.resource.set`, the `refreservation=auto` added to keep it thick was therefore written even though the resize failed, leaving a larger reservation on a volume that never grew. The same happened with a caller-supplied `refreservation`, and a `readonly: off` sent in the same request was applied even though ZFS still judged the resize against the stored read-only value. The resize tests brought in from master, and one S3 bucket test, also still called `zfs.resource.query`, and the resize tests expected the old `pool.dataset.update` error text.
## Solution
Added a set rule that rejects any `volsize` in the request while the volume is currently read-only or locked, so nothing is written and the caller is told to turn read-only off or unlock the volume first. `keystatus` is now read alongside the other properties so the rule can tell a locked volume apart. The resize and S3 bucket integration tests use `zfs.resource.list`, the resize tests expect the new messages, and there is a new case covering a grow that also turns `readonly` off.
Pass a ZFSResourceSetArgsData to zfs.resource.set_impl
## Problem
`zfs.resource.set_impl` took a path plus loose `properties`/`user_properties`/`inherit`/`bypass` arguments, unlike `create_impl` which takes a model. Internal callers handed raw dicts straight to libzfs, so a bad property name or value only surfaced as a libzfs error part way through the write.
## Solution
- **Typed input**: `set_impl` takes a `ZFSResourceSetArgsData`, the same model the public `zfs.resource.set` uses, so every caller's values are validated when the model is built, before anything is written. `touched_names` and `changed_fields` read the model too; the event, audit and quota/refquota `none` handling are unchanged.
- **Private fields**: `ZFSResourceSetArgsData` gains a `Private` `bypass` (honoured by both `set` and `set_impl`), and `ZFSResourceSetProperties` gains a `Private` `volthreading` for the iSCSI and NVMe-oF zvol handling. API callers still cannot supply either.
- **Callers**: every internal caller builds the model inline. `pool.dataset.update_impl` keeps its dict arguments since the HA peer calls it by name, and coerces them into the model. The tier special_small_blocks constants are ints now that they go through the typed model.
- **System dataset encryption**: when the pool root is passphrase-encrypted, `setup_datasets` added `encryption=off` to the comparison for existing system datasets too, so an encrypted child would have been sent an encryption change that ZFS refuses and setup would fail. Encryption is left out of the update comparison; creation still sets it.
Measure volume reservation headroom the way master did
## Problem
The reservation headroom checks drifted from master in ways that refused requests ZFS and master accept:
- **set**: headroom was measured as `requested - current refreservation` on every refreservation change. The kernel only charges the part of a reservation above the data the volume already holds, so converting a sparse volume that has data to thick was refused even with `force_size`. For example, an 80G sparse volume with 60G written and 50G free needs 20G for `refreservation=80G`, but was refused as needing 80G.
- **create**: a new volume was measured against the nearest ancestor's `available - usedbyrefreservation`. When that ancestor has a refquota, `available` is already clamped to it, so the refreservation was counted twice. Under a nearly empty parent with refquota=10G and refreservation=10G on a 5T pool, every thick volume create was refused, where master allowed up to 8G.
## Solution
- **set**: the volume headroom check runs only when `volsize` changes, as `pool.dataset.update` did on master. A refreservation-only change is left to ZFS, which refuses what it cannot back.
- **create**: the check measures against the nearest existing ancestor's `available`, as both `pool.dataset.create` and `zfs.resource.create` did on master.
Encode zvol names when matching snapshot devices to iSCSI extents
## Problem
The iSCSI extent delegate looked up extents on the snapshot devices about to be hidden by `zvol/<dataset>@<snap>` built from the raw dataset name, but an extent stores its path in the encoded form where a space becomes `+`. A zvol or snapshot with a space in its name therefore never matched, and `snapdev=hidden` removed the device node from under a live extent, which the attachment scan it replaced caught correctly.
## Solution
Build the lookup paths with `zvol_name_to_path`, the same encoder the extent disk choices come from, and pin it with unit tests over names containing spaces, including the exact path list passed to `iscsi.extent.query`.
Resolve snapshot names to their dataset in the locked-path check
## Problem
`pool.dataset.path_in_locked_datasets` opened the resource named by the path and read its `crypto()`; a snapshot-backed iSCSI extent, NVMe-oF namespace or VM disk (`zvol/<dataset>@<snap>`) therefore reached it with an `@` name, pylibzfs returned a snapshot object with no `crypto`, and the AttributeError escaped, so `iscsi.extent.create` on such an extent inserted its row and then crashed in `get_instance`, and every later extent query failed on the orphan.
## Solution
A snapshot holds no keys, so its lock state is its dataset's: strip the snapshot suffix before the parent walk, which also lets the ancestor-prefix check see the dataset. Pinned with a unit test over the three accepted path forms.