Skip to content
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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mirage-block-unix

Unix implementation of the Mirage `BLOCK_DEVICE` interface.

This interface exposes raw. unbuffered I/O (via `O_DIRECT`) to files
and block devices.
This module provides raw I/O to files and block devices with as little
caching as possible.

E-mail: <mirageos-devel@lists.xenproject.org>
9 changes: 9 additions & 0 deletions lib/blkgetsize_stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@

#include <sys/types.h>
#include <sys/stat.h>
#ifndef _WIN32
#include <sys/ioctl.h>
#endif

#include <fcntl.h>
#include <string.h>
Expand Down Expand Up @@ -72,6 +74,13 @@ int blkgetsize(int fd, uint64_t *psize)
return ret;
}

#elif _WIN32

int blkgetsize(int fd, uint64_t *psize)
{
return 0; /* Will never be called because there are no block device file */
}

#else
# error "Unable to query block device size: unsupported platform, please report."
#endif
Expand Down
19 changes: 16 additions & 3 deletions lib/block.ml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

module Log = (val Logs.src_log src : Logs.LOG)

let is_win32 = Sys.os_type = "Win32"

type buf = (char, Bigarray.int8_unsigned_elt, Bigarray.c_layout) Bigarray.Array1.t

type id = string
Expand Down Expand Up @@ -62,6 +64,7 @@ type t = {
m: Lwt_mutex.t;
name: string;
mutable info: info;
use_fsync: bool;
}

let id { name } = name
Expand Down Expand Up @@ -113,7 +116,13 @@ let remove_prefix prefix x =

let connect name =
let buffered, name = remove_prefix buffered_prefix name in
let openfile = if buffered then Raw.openfile_buffered else Raw.openfile_unbuffered in
let openfile, use_fsync = match buffered, is_win32 with
| true, _ -> Raw.openfile_buffered, false
| false, false -> Raw.openfile_unbuffered, false
| false, true ->
(* We can't use O_DIRECT or F_NOCACHE on Win32, so for now
we will use `fsync` after every write. *)
Raw.openfile_buffered, true in
(* first try read/write and then fall back to read/only *)
try
let fd, read_write =
Expand All @@ -130,7 +139,7 @@ let connect name =
let size_sectors = Int64.(div x (of_int sector_size)) in
let fd = Lwt_unix.of_unix_file_descr fd in
let m = Lwt_mutex.create () in
return (`Ok { fd = Some fd; m; name; info = { sector_size; size_sectors; read_write } })
return (`Ok { fd = Some fd; m; name; info = { sector_size; size_sectors; read_write }; use_fsync })
with e ->
Log.err (fun f -> f "connect %s: failed to open file" name);
return (`Error (`Unknown (Printf.sprintf "connect %s: failed to open file" name)))
Expand Down Expand Up @@ -233,6 +242,8 @@ let rec write x sector_start buffers = match buffers with
Lwt_unix.LargeFile.lseek fd offset Unix.SEEK_SET >>= fun _ ->
really_write fd b
) >>= fun () ->
( if x.use_fsync then Lwt_unix.fsync fd else Lwt.return () )
>>= fun () ->
return (`Ok ())
) >>= function
| `Ok () ->
Expand All @@ -246,7 +257,9 @@ let resize t new_size_sectors =
match t.fd with
| None -> return (`Error `Disconnected)
| Some fd ->
lwt_wrap_exn t "ftruncate" new_size_bytes
if is_win32
then return (`Error `Unimplemented)
else lwt_wrap_exn t "ftruncate" new_size_bytes
(fun () ->
Lwt_unix.LargeFile.ftruncate fd new_size_bytes
>>= fun () ->
Expand Down
5 changes: 4 additions & 1 deletion lib/odirect_stubs.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ CAMLprim value stub_openfile_direct(value filename, value rw, value perm){
CAMLparam3(filename, rw, perm);
CAMLlocal1(result);
int fd;

#ifdef _WIN32
caml_failwith("O_DIRECT is not supported on Win32");
#else
const char *filename_c = strdup(String_val(filename));

enter_blocking_section();
Expand All @@ -65,4 +67,5 @@ CAMLprim value stub_openfile_direct(value filename, value rw, value perm){
if (fd == -1) uerror("open", filename);
if (ret < 0) uerror("open", filename);
CAMLreturn(Val_int(fd));
#endif /* _WIN32 */
}
29 changes: 17 additions & 12 deletions lib_test/test.ml
Original file line number Diff line number Diff line change
Expand Up @@ -202,17 +202,22 @@ let test_flush () =
) in
Lwt_main.run t

let not_implemented_on_windows = [
"test resize" >:: test_resize;
]

let tests = [
"test ENOENT" >:: test_enoent;
"test open read" >:: test_open_read;
(* Doesn't work on travis
"test opening a block device" >:: test_open_block;
*)
"test read/write after last sector" >:: test_eof;
"test flush" >:: test_flush;
"test write then read" >:: test_write_read;
"test that writes fail if the buffer has a bad length" >:: test_buffer_wrong_length;
] @ (if Sys.os_type <> "Win32" then not_implemented_on_windows else [])

let _ =
let suite = "block" >::: [
"test ENOENT" >:: test_enoent;
"test open read" >:: test_open_read;
(* Doesn't work on travis
"test opening a block device" >:: test_open_block;
*)
"test read/write after last sector" >:: test_eof;
"test resize" >:: test_resize;
"test flush" >:: test_flush;
"test write then read" >:: test_write_read;
"test that writes fail if the buffer has a bad length" >:: test_buffer_wrong_length;
] in
let suite = "block" >::: tests in
OUnit2.run_test_tt_main (ounit2_of_ounit1 suite)
9 changes: 7 additions & 2 deletions lib_test/utils.ml
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ let find_unused_file () =
(* Find a filename which doesn't exist *)
let rec does_not_exist i =
let name = Printf.sprintf "%s/mirage-block-test.%d.%d"
Filename.temp_dir_name (Unix.getpid ()) i in
(Filename.get_temp_dir_name ()) (Unix.getpid ()) i in
if Sys.file_exists name
then does_not_exist (i + 1)
else name in
Expand All @@ -169,7 +169,12 @@ let with_temp_file f =
let path = find_unused_file () in
finally
(fun () ->
ignore_string (run "dd" [ "if=/dev/zero"; "of=" ^ path; "seek=1024"; "bs=1048576"; "count=1"]);
let fd = Unix.openfile path [ Unix.O_CREAT; Unix.O_TRUNC; Unix.O_WRONLY ] 0o0644 in
finally
(fun () ->
ignore(Unix.lseek fd 1048575 Unix.SEEK_CUR);
ignore(Unix.write fd "\000" 0 1)) (* will write at least 1 *)
(fun () -> Unix.close fd);
f path
) (fun () ->
rm_f path
Expand Down