From eb1a104f385f375a74319695e1a59f6f82e6384e Mon Sep 17 00:00:00 2001 From: Gabriel Schneider Date: Tue, 22 Sep 2026 11:50:09 -0300 Subject: 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 --- src/fs.zig | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) (limited to 'src/fs.zig') diff --git a/src/fs.zig b/src/fs.zig index bd9cbd9..83cea68 100644 --- a/src/fs.zig +++ b/src/fs.zig @@ -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 } }); -- cgit v1.3