diff options
| author | Gabriel Schneider <[email protected]> | 2026-09-22 11:50:09 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-09-22 11:50:09 -0300 |
| commit | eb1a104f385f375a74319695e1a59f6f82e6384e (patch) | |
| tree | b6a1f48588512ce677f41adeaae85a53655c4781 /src/fs.zig | |
| parent | b7fc01550c7bde290cf14276d94193b5b4031dc8 (diff) | |
| download | cloud9-eb1a104f385f375a74319695e1a59f6f82e6384e.tar.gz cloud9-eb1a104f385f375a74319695e1a59f6f82e6384e.zip | |
fs: a parked job whose fid was clunked is answered, not asked again
A client that gives up on a parked open sends Tclunk for its fid without
a Tflush; the fid goes, the parked job stays. On retry the job went back
to the backend, which did the work -- opened a handle, made an object --
and the reply then found no fid and dropped it, handle and all. Now the
retry looks for the fid first and answers "fid unknown" without asking.
Found by an adversarial review of pardes's use of the engine.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Diffstat (limited to 'src/fs.zig')
| -rw-r--r-- | src/fs.zig | 30 |
1 files changed, 29 insertions, 1 deletions
@@ -693,7 +693,17 @@ pub fn Server(comptime Backend: type, comptime opts: Options) type { return null; } const sl = &s.slots[i]; - if (sl.holdsJob()) return s.resumeJob(i); + if (sl.holdsJob()) { + // Its fid may have been clunked while it waited: then there + // is nobody to answer, and asking the backend would make it + // do the work -- open a handle, make an object -- for no one. + if (s.findFid(sl.fid) == null) { + s.fail(sl.tag, e_unknown_fid); + sl.* = .{}; + return s.retry(); + } + return s.resumeJob(i); + } sl.retried = true; sl.parked = false; return sl.req; @@ -2221,6 +2231,24 @@ test "fs server: a parked open, truncate and clunk complete on retry, and a walk try testing.expectEqualStrings(e_again, got.msg.rerror.ename); h.fsys.park_lookups = false; + // A parked open whose fid is clunked meanwhile is answered for the + // clunk's sake and never asked again: the backend would otherwise open + // a handle for nobody. + _ = try h.walkTo(16, 5, &.{ "1", "tag" }); + h.fsys.park_opens = true; + try h.send(17, .{ .topen = .{ .fid = 5, .mode = oread } }); + try h.quiet(); + try h.send(18, .{ .tclunk = .{ .fid = 5 } }); + got = try h.reap(); + try testing.expect(got.msg == .rclunk); + h.fsys.park_opens = false; + const asked = h.fsys.calls; + h.pump(); + got = try h.reap(); + try testing.expectEqual(@as(u16, 17), got.tag); + try testing.expectEqualStrings(e_unknown_fid, got.msg.rerror.ename); + try testing.expectEqual(asked, h.fsys.calls); + // A flush reaches a parked job the way it reaches a parked read. h.fsys.park_opens = true; try h.send(14, .{ .topen = .{ .fid = 2, .mode = oread } }); |
