XXNU Source Handbook Download offline version from here
Part 10 · Chapter 10.09

Advisory byte-range locks and file leases

VFS · Descriptors · UNIX rights · Namespace changes

Advisory locks coordinate owners of file byte ranges. File leases notify a holder when another operation needs conflicting access. Their state, ownership and wakeup protocols are different even though both can make a file operation wait.

Which owner survives dup, fork and close?

fcntl selects POSIX or open-file-description semantics before VNOP_ADVLOCK. POSIX requests use the process as identity; OFD requests derive identity from the fileglob. flock also uses fileglob identity but sets its own whole-file semantics. Duplicated descriptors can therefore share an OFD/flock owner while process locks have a process-based release rule. fcntl dispatch, flock dispatch.

struct lockf records inclusive start/end (-1 means EOF), type, identity, semantics flags, vnode/list backpointers and a queue of requests blocked by this lock. lf_owner is a process only where ownership can be established safely: ordinary POSIX locks, or confined OFD cases. The list hangs from vnode.v_lockf and is protected by v_lock. Structure, admission/owner setup.

Normalize, find conflicts and edit intervals

lf_advlock converts a flock range to inclusive bounds. The caller has already adjusted SEEK_CUR; SEEK_END obtains current vnode size with overflow checks. Zero length extends to EOF, negative length covers bytes before the supplied start, and invalid negative/overflowing ranges fail. It allocates a request and invokes the set/clear/get operation under v_lock. Normalization.

lf_getblock locates overlapping conflicting owners/types. A nonblocking conflicting set frees its request and returns EAGAIN. After conflicts are gone, lf_setlock handles six overlap cases with the same owner's existing ranges: none, exact equality, either containment, and overlap at either end. It can split, replace, shorten or merge intervals and move/wake blocked requests. Unlock uses corresponding interval editing. Conflict and insertion, clear, split.

Illustrative operation: owner A holds write range [0,99], then unlocks [40,59]. Its state becomes [0,39] and [60,99]; a waiter for byte 50 may now proceed while a waiter for byte 70 remains blocked. An interval is not tied to the descriptor number used for that individual request.

Sleep and deadlock checks

A blocking request is linked on the conflicting lock's lf_blkhd, with lf_next identifying the blocker, then sleeps while releasing v_lock. POSIX deadlock detection examines process thread wait channels and related blocking state under lf_dead_lock. If inspecting another vnode would require a conflicting mutex, the code drops locks, pauses and restarts the scan. OFD locks do not implement this same deadlock check. Detection and retry.

Advisory byte-range locks and file leases diagram
Advisory byte-range locks and file leases diagram · Open SVG
Mermaid source
flowchart TD
    R[Normalized request] --> C[Search conflicting owner/range]
    C -->|none| I[Split or merge own ranges]
    C -->|nonblocking| E[EAGAIN and free request]
    C -->|blocking| D[Applicable deadlock check]
    D --> Q[Link request to blocker and sleep]
    Q --> W[Wake: unlink stale wait relation]
    W -->|no error| C
    W -->|signal / timeout / abort| F[Transfer dependent waiters and free request]

Wakeup is not automatically a grant. A spurious wake must remove the old queue link before retrying, otherwise a second insertion could create a cycle. Interrupted/timed-out requests adjust any donation and transfer/wake requests blocked behind them. F_ABORT becomes EBADF; timeout sleep errors become ETIMEDOUT. Wake cleanup.

bsd/kern/kern_lockf.c, lines 790–797:

			TAILQ_REMOVE(&lock->lf_next->lf_blkhd, lock, lf_block);
#if IMPORTANCE_INHERITANCE
			/*
			 * Adjust the boost on lf_next.
			 */
			lf_adjust_assertion(lock->lf_next);
#endif /* IMPORTANCE_INHERITANCE */
			lock->lf_next = NULL;

Closing a file and disposing a transferred reference

Descriptor close can release POSIX locks for the process even when other references keep the fileglob alive. OFD/flock release belongs to open-file ownership. The process context passed to a drop therefore matters: failed SCM_RIGHTS externalization uses UNP_FG_NOPROC so discarding an undelivered message reference does not accidentally act like the recipient closing an already open file. Process lock cleanup, failed receive disposal. This is a useful example of why reducing every cleanup to “decrement the reference count” loses behavior.

Lease state and break requests

Under CONFIG_FILE_LEASES, each vnode has file_lease records containing fileglob, owning PID, read/write type, pending flags and separate release/downgrade timestamps. vnode_setlease checks admission policy and calls acquisition or release. Leases are not entries in v_lockf. Representation, lease entry.

vnode_breaklease derives access from open flags, applies special dataless/read-context exemptions and checks whether another process holds conflicting lease state. A read can require downgrade of an exclusive lease; a write/truncate can require release. It marks pending state and posts NOTE_LEASE_DOWNGRADE or NOTE_LEASE_RELEASE. A holder can receive both with different start times when later access escalates. Conflict and notification.

For an O_NONBLOCK breaker the event has already been sent when EWOULDBLOCK is returned. A blocking breaker waits for release/downgrade; timeout handling can force the pending change. Success is not unconditional veto power for the original holder. Wait selection, timeout transitions.

Directory mutation calls vnode_breakdirlease and may obtain the parent from cached identity or a filesystem parent-ID lookup. That helper explicitly makes a best-effort parent lookup. Vnode reclaim calls vnode_revokelease, removes all records and wakes breakers. Directory and reclaim. Remote/filesystem-specific lock providers can override VNOP behavior; this chapter explains the local generic lockf implementation and VFS lease protocol rather than an absent network lock manager.

Search the handbook

Search every chapter, interface and code excerpt.

    Diagram

    Source preview

    Open full file