8000 eio_linux: read_exactly fails to update file_offset by talex5 · Pull Request #438 · ocaml-multicore/eio · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

eio_linux: read_exactly fails to update file_offset #438

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 21 additions & 11 deletions lib_eio_linux/eio_linux.ml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
(*
* Copyright (C) 2020-2021 Anil Madhavapeddy
* Copyright (C) 2023 Thomas Leonard
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
Expand All @@ -14,6 +15,8 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*)

[@@@alert "-unstable"]

let src = Logs.Src.create "eio_linux" ~doc:"Effect-based IO system for Linux/io-uring"
module Log = (val Logs.src_log src : Logs.LOG)

Expand Down Expand Up @@ -111,6 +114,11 @@ module FD = struct
let uring_file_offset t =
if t.seekable then Optint.Int63.minus_one else Optint.Int63.zero

let file_offset t = function
| Some x -> `Pos x
| None when t.seekable -> `Seekable_current
| None -> `Nonseekable_current

let fstat t =
(* todo: use uring *)
try
Expand Down Expand Up @@ -155,7 +163,11 @@ let get_dir_fd_opt t = Eio.Generic.probe t Dir_fd

type rw_req = {
op : [`R|`W];
file_offset : Optint.Int63.t;
file_offset : [
| `Pos of Optint.Int63.t (* Read from here + cur_off *)
| `Seekable_current
| `Nonseekable_current
];
fd : FD.t;
len : amount;
buf : Uring.Region.chunk;
Expand Down Expand Up @@ -291,6 +303,12 @@ let rec submit_rw_req st ({op; file_offset; fd; buf; len; cur_off; action} as re
let len = match len with Exactly l | Upto l -> l in
let len = len - cur_off in
let retry = with_cancel_hook ~action st (fun () ->
let file_offset =
match file_offset with
| `Pos x -> Optint.Int63.add x (Optint.Int63.of_int cur_off)
| `Seekable_current -> Optint.Int63.minus_one
| `Nonseekable_current -> Optint.Int63.zero
in
match op with
|`R -> Uring.read_fixed uring ~file_offset fd ~off ~len (Read req)
|`W -> Uring.write_fixed uring ~file_offset fd ~off ~len (Write req)
Expand All @@ -306,11 +324,7 @@ let rec submit_rw_req st ({op; file_offset; fd; buf; len; cur_off; action} as re
let errno_is_retry = function -62 | -11 | -4 -> true |_ -> false

let enqueue_read st action (file_offset,fd,buf,len) =
let file_offset =
match file_offset with
| Some x -> x
| None -> FD.uring_file_offset fd
in
let file_offset = FD.file_offset fd file_offset in
let req = { op=`R; file_offset; len; fd; cur_off = 0; buf; action } in
Ctf.label "read";
submit_rw_req st req
Expand Down Expand Up @@ -378,11 +392,7 @@ let rec enqueue_close t action fd =
Queue.push (fun t -> enqueue_close t action fd) t.io_q

let enqueue_write st action (file_offset,fd,buf,len) =
let file_offset =
match file_offset with
| Some x -> x
| None -> FD.uring_file_offset fd
in
let file_offset = FD.file_offset fd file_offset in
let req = { op=`W; file_offset; len; fd; cur_off = 0; buf; action } in
Ctf.label "write";
submit_rw_req st req
Expand Down
28 changes: 27 additions & 1 deletion lib_eio_linux/tests/test.ml
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,31 @@ let test_no_sqe () =
raise Exit
with Exit -> ()

let test_read_exact () =
Eio_linux.run ~queue_depth:4 ~n_blocks:1 @@ fun env ->
let ( / ) = Eio.Path.( / ) in
let path = env#cwd / "test.data" in
let msg = "hello" in
Eio.Path.save path ("!" ^ msg) ~create:(`Exclusive 0o600);
Switch.run @@ fun sw ->
let fd = Eio_linux.Low_level.openat2 ~sw
~access:`R
~flags:Uring.Open_flags.empty
~perm:0
~resolve:Uring.Resolve.empty
"test.data"
in
Eio_linux.Low_level.with_chunk ~fallback:(fun () -> assert false) @@ fun chunk ->
(* Try to read one byte too far. If it's not updating the file offset, it will
succeed. *)
let len = String.length msg + 1 in
try
Eio_linux.Low_level.read_exactly ~file_offset:Optint.Int63.one fd chunk len;
assert false
with End_of_file ->
let got = Uring.Region.to_string chunk ~len:(String.length msg) in
if got <> msg then Fmt.failwith "%S vs %S" got msg

let () =
let open Alcotest in
run "eio_linux" [
Expand All @@ -134,6 +159,7 @@ let () =
test_case "poll_add" `Quick test_poll_add;
test_case "poll_add_busy" `Quick test_poll_add_busy;
test_case "iovec" `Quick test_iovec;
test_case "no-sqe" `Quick test_no_sqe;
test_case "no_sqe" `Quick test_no_sqe;
test_case "read_exact" `Quick test_read_exact;
];
]
0