1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
//! Kernel-syscall wrappers for `flock(2)` acquire/release.
//!
//! Three entry points, each gated through
//! [`super::fs_filter::reject_remote_fs`] so a misconfigured lockfile
//! path on NFS / CIFS / SMB2 / CephFS / AFS / FUSE surfaces actionably
//! at open time rather than silently returning an unserialized fd:
//!
//! - [`materialize`] — create the lockfile inode without acquiring
//! a lock. Used by the DISCOVER phase of
//! `acquire_llc_plan` so the snapshot pass has a target inode
//! for the subsequent `/proc/locks` match without contending
//! with live acquirers.
//! - [`try_flock`] — non-blocking acquire. Returns `Ok(None)` on
//! `EWOULDBLOCK` so the caller can decide whether to retry, poll,
//! or surface contention.
//! - [`block_flock`] — blocking acquire. Parks the calling thread
//! in the kernel until the lock is available. Used after
//! [`try_flock`] returns `None` for callers that want to wait
//! indefinitely; callers with a deadline use
//! [`super::acquire::acquire_flock_with_timeout`] instead.
//!
//! All three open with `O_CREAT | O_RDWR | O_CLOEXEC | 0o666` so the
//! resulting fd matches the rest of the crate's lockfile contract:
//!
//! - `O_CLOEXEC` keeps the lock from leaking across `exec(2)` into
//! spawned subprocesses (cargo subcommands, build pipeline,
//! initramfs compressor) where the parent's `OwnedFd::drop`
//! would not release a child-held flock.
//! - 0o666 mode matches a peer first-acquire so the file's owner
//! and permissions don't depend on creation order.
use Result;
use OwnedFd;
use Path;
use FlockMode;
use reject_remote_fs;
/// Open a lockfile with the crate-wide flock contract: refuses
/// remote filesystems via [`reject_remote_fs`], then opens with
/// `O_CREAT | O_RDWR | O_CLOEXEC | 0o666`. The three module entry
/// points ([`materialize`], [`try_flock`], [`block_flock`]) share
/// this open shape; centralizing it here means a future flag change
/// (or an addition to the remote-fs deny-list) lands in one place
/// instead of drifting across three call sites.
///
/// `O_CLOEXEC` is mandatory: a leaked fd across `exec(2)` (cargo
/// subcommand, build-pipeline subprocess, initramfs compressor)
/// would keep the lock alive in the child after the parent's
/// `OwnedFd::drop`, producing phantom holders the next acquirer
/// would blame on the wrong pid.
///
/// 0o666 mode matches a peer first-acquire so the file's owner and
/// permissions don't depend on creation order.
/// Ensure the lockfile exists on disk without acquiring a lock.
/// Used by the DISCOVER phase of `acquire_llc_plan` (see
/// `discover_llc_snapshots` in `crate::vmm::host_topology`): the
/// snapshot pass needs every per-LLC lockfile's inode to exist so a
/// subsequent `/proc/locks` match has a target, but DISCOVER itself
/// must not contend with peer acquires.
///
/// Opens through [`open_lockfile`] so the resulting inode and fd
/// mode match what a first-time acquirer would create. Immediately
/// closes the fd — `OwnedFd::drop` releases the open-file
/// description and (since no flock was ever taken on this fd)
/// cannot release a lock held by a peer fd.
pub
/// Open a lock file and attempt `flock` with `LOCK_NB`.
///
/// Creates the file with mode 0o666 if absent. Returns
/// `Ok(Some(fd))` on successful acquire, `Ok(None)` on
/// `EWOULDBLOCK` (peer already holds an incompatible lock), and
/// propagates other errors. The returned fd owns the open-file
/// description; dropping it closes the fd AND releases the kernel
/// flock (the kernel releases `flock(2)` only when the last fd
/// referring to its OFD closes — `OwnedFd::drop` is what makes that
/// work).
///
/// `O_CLOEXEC` is mandatory: a leaked fd across `exec(2)` (cargo
/// subcommand, build-pipeline subprocess, initramfs compressor) would
/// keep the lock alive in the child process after the parent's
/// `OwnedFd::drop` runs, producing phantom holders the next acquirer
/// would blame on the wrong pid.
///
/// Calls `super::fs_filter::reject_remote_fs` before the open to
/// fail-fast on NFS / CIFS / SMB2 / CEPH / AFS / FUSE — see the
/// module-level rationale.
///
/// Accepts any `AsRef<Path>` so `&str`, `&Path`, `&PathBuf`, and
/// `String` callers all work without string-ifying round trips. LLC
/// lockfile paths are built as `String` via `format!` and cache
/// lockfile paths are built as `PathBuf` via `Path::join` — both
/// pass straight through.
/// Blocking variant of [`try_flock`]. Opens the lockfile (creating
/// it if absent), then issues a blocking `flock(2)` that parks the
/// caller in the kernel until the lock is available. Use after
/// [`try_flock`] returns `None` to wait for a live peer to finish.