summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/fs.zig30
1 files changed, 29 insertions, 1 deletions
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 } });