qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [RFC for-3.0 1/4] block: Add Rust interface


From: Max Reitz
Subject: [Qemu-devel] [RFC for-3.0 1/4] block: Add Rust interface
Date: Tue, 18 Apr 2017 15:58:24 -0000

This patch adds an FFI interface for block drivers written in Rust, the
language of the future. It's a very good interface, in fact, it's the
best interface there is. We are truly making QEMU great again!

Signed-off-by: Max Reitz <address@hidden>
---
 configure                               |    2 +
 Makefile                                |    6 +-
 Makefile.target                         |    2 +-
 block/rust/Cargo.toml                   |   10 +
 block/rust/src/interface/c_constants.rs |    8 +
 block/rust/src/interface/c_functions.rs |   37 ++
 block/rust/src/interface/c_structs.rs   |  587 ++++++++++++++++++
 block/rust/src/interface/mod.rs         | 1012 +++++++++++++++++++++++++++++++
 block/rust/src/lib.rs                   |    9 +
 9 files changed, 1671 insertions(+), 2 deletions(-)
 create mode 100644 block/rust/Cargo.toml
 create mode 100644 block/rust/src/interface/c_constants.rs
 create mode 100644 block/rust/src/interface/c_functions.rs
 create mode 100644 block/rust/src/interface/c_structs.rs
 create mode 100644 block/rust/src/interface/mod.rs
 create mode 100644 block/rust/src/lib.rs

diff --git a/configure b/configure
index be4d326ae0..f99d19e47b 100755
--- a/configure
+++ b/configure
@@ -745,6 +745,8 @@ if test "$mingw32" = "yes" ; then
   libs_qga="-lws2_32 -lwinmm -lpowrprof -liphlpapi -lnetapi32 $libs_qga"
 fi
 
+LIBS="-ldl $LIBS"
+
 werror=""
 
 for opt do
diff --git a/Makefile b/Makefile
index 6c359b2f86..5cf071fb30 100644
--- a/Makefile
+++ b/Makefile
@@ -368,9 +368,13 @@ Makefile: $(version-obj-y)
 libqemustub.a: $(stub-obj-y)
 libqemuutil.a: $(util-obj-y)
 
+.PHONY: rust_block_drivers_source
+rust/debug/libqemu_rust_block_drivers.a: rust_block_drivers_source
+       cd "$(SRC_PATH)/block/rust" && CARGO_TARGET_DIR="$(BUILD_DIR)/rust" 
cargo build
+
 ######################################################################
 
-COMMON_LDADDS = $(trace-obj-y) libqemuutil.a libqemustub.a
+COMMON_LDADDS = $(trace-obj-y) libqemuutil.a libqemustub.a 
rust/debug/libqemu_rust_block_drivers.a
 
 qemu-img.o: qemu-img-cmds.h
 
diff --git a/Makefile.target b/Makefile.target
index 7df2b8c149..0dc4c0a35b 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -201,7 +201,7 @@ all-obj-$(CONFIG_SOFTMMU) += $(io-obj-y)
 
 $(QEMU_PROG_BUILD): config-devices.mak
 
-COMMON_LDADDS = $(trace-obj-y) ../libqemuutil.a ../libqemustub.a
+COMMON_LDADDS = $(trace-obj-y) ../libqemuutil.a ../libqemustub.a 
../rust/debug/libqemu_rust_block_drivers.a
 
 # build either PROG or PROGW
 $(QEMU_PROG_BUILD): $(all-obj-y) $(COMMON_LDADDS)
diff --git a/block/rust/Cargo.toml b/block/rust/Cargo.toml
new file mode 100644
index 0000000000..13cdf068b3
--- /dev/null
+++ b/block/rust/Cargo.toml
@@ -0,0 +1,10 @@
+[package]
+name = "qemu-rust-block-drivers"
+version = "3.0.0"
+authors = ["Max Reitz <address@hidden>"]
+
+[dependencies]
+libc = "0.2.0"
+
+[lib]
+crate-type = ["staticlib"]
diff --git a/block/rust/src/interface/c_constants.rs 
b/block/rust/src/interface/c_constants.rs
new file mode 100644
index 0000000000..56919f1a04
--- /dev/null
+++ b/block/rust/src/interface/c_constants.rs
@@ -0,0 +1,8 @@
+use interface::c_structs::*;
+
+
+extern {
+    pub static child_file: BdrvChildRole;
+    pub static child_format: BdrvChildRole;
+    pub static child_backing: BdrvChildRole;
+}
diff --git a/block/rust/src/interface/c_functions.rs 
b/block/rust/src/interface/c_functions.rs
new file mode 100644
index 0000000000..1be8d85ccb
--- /dev/null
+++ b/block/rust/src/interface/c_functions.rs
@@ -0,0 +1,37 @@
+use interface::c_structs::*;
+use libc::{c_char,c_int,c_void,size_t};
+
+
+extern {
+    pub fn bdrv_is_read_only(bs: *mut BlockDriverState) -> bool;
+
+    pub fn bdrv_open_child(filename: *const c_char, options: *mut QDict,
+                           bdref_key: *const c_char,
+                           parent: *mut BlockDriverState,
+                           child_role: *const BdrvChildRole,
+                           allow_none: bool, errp: *mut *mut Error)
+        -> *mut BdrvChild;
+
+    pub fn bdrv_pread(child: *mut BdrvChild, offset: i64, buf: *mut c_void,
+                      bytes: c_int)
+        -> c_int;
+
+    pub fn bdrv_pwrite(child: *mut BdrvChild, offset: i64, buf: *const c_void,
+                       bytes: c_int)
+        -> c_int;
+
+    pub fn bdrv_register(bdrv: *mut BlockDriver);
+
+    pub fn error_get_pretty(err: *mut Error) -> *const c_char;
+
+    pub fn error_setg_internal(errp: *mut *mut Error, src: *const c_char,
+                               line: c_int, func: *const c_char,
+                               fmt: *const c_char, ...);
+
+    pub fn g_strdup(str: *const c_char) -> *mut c_char;
+
+    pub fn qemu_blockalign(bs: *mut BlockDriverState, size: size_t)
+        -> *mut c_void;
+
+    pub fn qemu_vfree(ptr: *mut c_void);
+}
diff --git a/block/rust/src/interface/c_structs.rs 
b/block/rust/src/interface/c_structs.rs
new file mode 100644
index 0000000000..74e342b0c7
--- /dev/null
+++ b/block/rust/src/interface/c_structs.rs
@@ -0,0 +1,587 @@
+use libc::{c_char,c_int,c_uint,c_ulong,c_void,size_t};
+
+
+const BLOCK_OP_TYPE_MAX: usize = 16;
+
+
+#[repr(C)]
+pub struct BlockDriver {
+    pub format_name: *const c_char,
+    pub instance_size: c_int,
+
+    pub is_filter: bool,
+
+    pub bdrv_recurse_is_first_non_filter: Option<
+            extern fn(bs: *mut BlockDriverState,
+                      candidate: *mut BlockDriverState)
+                -> bool
+        >,
+
+    pub bdrv_probe: Option<
+            extern fn(buf: *const c_char, buf_size: c_int,
+                      filename: *const c_char)
+                -> c_int
+        >,
+    pub bdrv_probe_device: Option<extern fn(filename: *const c_char) -> c_int>,
+
+    pub bdrv_parse_filename: Option<
+            extern fn(filename: *const c_char,
+                      options: *mut QDict,
+                      errp: *mut *mut Error)
+        >,
+    pub bdrv_needs_filename: bool,
+
+    pub supports_backing: bool,
+
+    pub bdrv_reopen_prepare: Option<
+            extern fn(reopen_state: *mut BDRVReopenState,
+                      queue: *mut BlockReopenQueue,
+                      errp: *mut *mut Error)
+                -> c_int
+        >,
+    pub bdrv_reopen_commit: Option<
+            extern fn(reopen_state: *mut BDRVReopenState)
+        >,
+    pub bdrv_reopen_abort: Option<
+            extern fn(reopen_state: *mut BDRVReopenState)
+        >,
+    pub bdrv_join_options: Option<
+            extern fn(options: *mut QDict, old_options: *mut QDict)
+        >,
+
+    pub bdrv_open: Option<
+            extern fn(bs: *mut BlockDriverState, options: *mut QDict,
+                      flags: c_int, errp: *mut *mut Error)
+                -> c_int
+        >,
+    pub bdrv_file_open: Option<
+            extern fn(bs: *mut BlockDriverState, options: *mut QDict,
+                      flags: c_int, errp: *mut *mut Error)
+                -> c_int
+        >,
+    pub bdrv_close: Option<extern fn(bs: *mut BlockDriverState)>,
+    pub bdrv_create: Option<
+            extern fn(filename: *const c_char, opts: *mut QemuOpts,
+                      errp: *mut *mut Error)
+                -> c_int
+        >,
+    pub bdrv_set_key: Option<DeprecatedFn>,
+    pub bdrv_make_empty: Option<extern fn(bs: *mut BlockDriverState)>,
+
+    pub bdrv_refresh_filename: Option<
+            extern fn(bs: *mut BlockDriverState, options: *mut QDict)
+        >,
+
+    pub bdrv_aio_readv: Option<DeprecatedFn>,
+    pub bdrv_aio_writev: Option<DeprecatedFn>,
+    pub bdrv_aio_flush: Option<DeprecatedFn>,
+    pub bdrv_aio_pdiscard: Option<DeprecatedFn>,
+
+    pub bdrv_co_readv: Option<DeprecatedFn>,
+    pub bdrv_co_preadv: Option<
+            extern fn(bs: *mut BlockDriverState, offset: u64, bytes: u64,
+                      qiov: *mut QEMUIOVector, flags: c_int)
+                -> c_int
+        >,
+    pub bdrv_co_writev: Option<DeprecatedFn>,
+    pub bdrv_co_writev_flags: Option<DeprecatedFn>,
+    pub bdrv_co_pwritev: Option<
+            extern fn(bs: *mut BlockDriverState, offset: u64, bytes: u64,
+                      qiov: *mut QEMUIOVector, flags: c_int)
+                -> c_int
+        >,
+
+    pub bdrv_co_pwrite_zeroes: Option<
+            extern fn(bs: *mut BlockDriverState, offset: i64, count: c_int,
+                      flags: c_int /* BdrvRequestFlags */)
+                -> c_int
+        >,
+    pub bdrv_co_pdiscard: Option<
+            extern fn(bs: *mut BlockDriverState, offset: i64, count: c_int)
+                -> c_int
+        >,
+    pub bdrv_co_get_block_status: Option<
+            extern fn(bs: *mut BlockDriverState, sector_num: i64,
+                      nb_sectors: c_int, pnum: *mut c_int,
+                      file: *mut *mut BlockDriverState)
+                -> i64
+        >,
+
+    pub bdrv_invalidate_cache: Option<
+            extern fn(bs: *mut BlockDriverState, errp: *mut *mut Error)
+        >,
+    pub bdrv_inactivate: Option<extern fn(bs: *mut BlockDriverState) -> c_int>,
+
+    pub bdrv_co_flush: Option<extern fn(bs: *mut BlockDriverState) -> c_int>,
+
+    pub bdrv_co_flush_to_disk: Option<
+            extern fn(bs: *mut BlockDriverState) -> c_int
+        >,
+
+    pub bdrv_co_flush_to_os: Option<
+            extern fn(bs: *mut BlockDriverState) -> c_int
+        >,
+
+    pub protocol_name: *const c_char,
+    pub bdrv_truncate: Option<
+            extern fn(bs: *mut BlockDriverState, offset: i64,
+                      errp: *mut *mut Error)
+                -> c_int
+        >,
+
+    pub bdrv_getlength: Option<extern fn(bs: *mut BlockDriverState) -> c_int>,
+    pub has_variable_length: bool,
+    pub bdrv_get_allocated_file_size: Option<
+            extern fn(bs: *mut BlockDriverState) -> i64
+        >,
+
+    pub bdrv_co_pwritev_compressed: Option<
+            extern fn(bs: *mut BlockDriverState, offset: u64, bytes: u64,
+                      qiov: *mut QEMUIOVector)
+                -> c_int
+        >,
+
+    pub bdrv_snapshot_create: Option<
+            extern fn(bs: *mut BlockDriverState, sn_info: *mut 
QEMUSnapshotInfo)
+                -> c_int
+        >,
+    pub bdrv_snapshot_goto: Option<
+            extern fn(bs: *mut BlockDriverState, snapshot_id: *const c_char)
+                -> c_int
+        >,
+    pub bdrv_snapshot_delete: Option<
+            extern fn(bs: *mut BlockDriverState, snapshot_id: *const c_char,
+                      name: *const c_char, errp: *mut *mut Error)
+                -> c_int
+        >,
+    pub bdrv_snapshot_list: Option<
+            extern fn(bs: *mut BlockDriverState,
+                      psn_info: *mut *mut QEMUSnapshotInfo)
+                -> c_int
+        >,
+    pub bdrv_snapshot_load_tmp: Option<
+            extern fn(bs: *mut BlockDriverState, snapshot_id: *const c_char,
+                      name: *const c_char, errp: *mut *mut Error)
+                -> c_int
+        >,
+
+    pub bdrv_get_info: Option<
+            extern fn(bs: *mut BlockDriverState, bdi: *mut BlockDriverInfo)
+                -> c_int
+        >,
+    /* Note that the return object should be allocated in the C program */
+    pub bdrv_get_specific_info: Option<
+            extern fn(bs: *mut BlockDriverState) -> *mut ImageInfoSpecific
+        >,
+
+    pub bdrv_save_vmstate: Option<
+            extern fn(bs: *mut BlockDriverState, qiov: *mut QEMUIOVector,
+                      pos: i64)
+                -> c_int
+        >,
+    pub bdrv_load_vmstate: Option<
+            extern fn(bs: *mut BlockDriverState, qiov: *mut QEMUIOVector,
+                      pos: i64)
+                -> c_int
+        >,
+
+    pub bdrv_change_backing_file: Option<
+            extern fn(bs: *mut BlockDriverState,
+                      backing_file: *const c_char, backing_fmt: *const c_char)
+                -> c_int
+        >,
+
+    pub bdrv_is_inserted: Option<extern fn(bs: *mut BlockDriverState) -> bool>,
+    pub bdrv_media_changed: Option<
+            extern fn(bs: *mut BlockDriverState) -> c_int
+        >,
+    pub bdrv_eject: Option<
+            extern fn(bs: *mut BlockDriverState, eject_flag: bool)
+        >,
+    pub bdrv_lock_medium: Option<
+            extern fn(bs: *mut BlockDriverState, locked: bool)
+        >,
+
+    pub bdrv_aio_ioctl: Option<DeprecatedFn>,
+    pub bdrv_co_ioctl: Option<
+            extern fn(bs: *mut BlockDriverState, req: c_ulong, buf: *mut 
c_void)
+                -> c_int
+        >,
+
+    pub create_opts: *mut QemuOptsList,
+
+    pub bdrv_check: Option<
+            extern fn(bs: *mut BlockDriverState, result: *mut BdrvCheckResult,
+                      fix: c_int /* BdrvCheckResult */)
+                -> c_int
+        >,
+
+    pub bdrv_amend_options: Option<
+            extern fn(bs: *mut BlockDriverState, opts: *mut QemuOpts,
+                      status_cb: BlockDriverAmendStatusCB,
+                      cb_opaque: *mut c_void)
+                -> c_int
+        >,
+
+    pub bdrv_debug_event: Option<
+            extern fn(bs: *mut BlockDriverState,
+                      event: c_int /* BlkdebugEvent */)
+        >,
+
+    pub bdrv_debug_breakpoint: Option<
+            extern fn(bs: *mut BlockDriverState, event: *const c_char,
+                      tag: *const c_char)
+                -> c_int
+        >,
+    pub bdrv_debug_remove_breakpoint: Option<
+            extern fn(bs: *mut BlockDriverState, tag: *const c_char) -> c_int
+        >,
+    pub bdrv_debug_resume: Option<
+            extern fn(bs: *mut BlockDriverState, tag: *const c_char) -> c_int
+        >,
+    pub bdrv_debug_is_suspended: Option<
+            extern fn(bs: *mut BlockDriverState, tag: *const c_char) -> bool
+        >,
+
+    pub bdrv_refresh_limits: Option<
+            extern fn(bs: *mut BlockDriverState, errp: *mut *mut Error)
+        >,
+
+    pub bdrv_has_zero_init: Option<
+            extern fn(bs: *mut BlockDriverState) -> c_int
+        >,
+
+    pub bdrv_detach_aio_context: Option<extern fn(bs: *mut BlockDriverState)>,
+
+    pub bdrv_attach_aio_context: Option<
+            extern fn(bs: *mut BlockDriverState, new_context: *mut AioContext)
+        >,
+
+    pub bdrv_io_plug: Option<extern fn(bs: *mut BlockDriverState)>,
+    pub bdrv_io_unplug: Option<extern fn(bs: *mut BlockDriverState)>,
+
+    pub bdrv_probe_blocksizes: Option<
+            extern fn(bs: *mut BlockDriverState, bsz: *mut BlockSizes)
+                -> c_int
+        >,
+    pub bdrv_probe_geometry: Option<
+            extern fn(bs: *mut BlockDriverState, geo: *mut HDGeometry)
+                -> c_int
+        >,
+
+    pub bdrv_drain: Option<extern fn(bs: *mut BlockDriverState)>,
+
+    pub bdrv_add_child: Option<
+            extern fn(parent: *mut BlockDriverState,
+                      child: *mut BlockDriverState,
+                      errp: *mut *mut Error)
+        >,
+    pub bdrv_del_child: Option<
+            extern fn(parent: *mut BlockDriverState,
+                      child: *mut BlockDriverState,
+                      errp: *mut *mut Error)
+        >,
+
+    pub bdrv_check_perm: Option<
+            extern fn(bs: *mut BlockDriverState, perm: u64, shared: u64,
+                      errp: *mut *mut Error)
+                -> c_int
+        >,
+    pub bdrv_set_perm: Option<
+            extern fn(bs: *mut BlockDriverState, perm: u64, shared: u64)
+        >,
+    pub bdrv_abort_perm_update: Option<extern fn(bs: *mut BlockDriverState)>,
+
+    pub bdrv_child_perm: Option<
+            extern fn(bs: *mut BlockDriverState, c: *mut BdrvChild,
+                      role: *const BdrvChildRole,
+                      parent_perm: u64, parent_shared: u64,
+                      nperm: *mut u64, nshared: *mut u64)
+        >,
+
+    pub list: QListEntry<BlockDriver>,
+}
+
+#[repr(C)]
+pub struct BlockDriverState {
+    pub open_flags: c_int,
+    pub read_only: bool,
+    pub encrypted: bool,
+    pub valid_key: bool,
+    pub sg: bool,
+    pub probed: bool,
+
+    pub drv: *mut BlockDriver,
+    pub opaque: *mut c_void,
+
+    pub aio_context: *mut AioContext,
+    pub aio_notifiers: *mut BdrvAioNotifier,
+    pub walking_aio_notifiers: bool,
+
+    pub filename: [c_char; 4096],
+    pub backing_file: [c_char; 4096],
+
+    pub backing_format: [c_char; 16],
+
+    pub full_open_options: *mut QDict,
+    pub exact_filename: [c_char; 4096],
+
+    pub backing: *mut BdrvChild,
+    pub file: *mut BdrvChild,
+
+    pub bl: BlockLimits,
+
+    pub supported_write_flags: c_uint,
+    pub supported_zero_flags: c_uint,
+
+    pub node_name: [c_char; 32],
+    pub node_list: QTailQEntry<BlockDriverState>,
+    pub bs_list: QTailQEntry<BlockDriverState>,
+    pub monitor_list: QTailQEntry<BlockDriverState>,
+    pub refcnt: c_int,
+
+    pub op_blockers: [QListHead<BdrvOpBlocker>; BLOCK_OP_TYPE_MAX],
+
+    pub job: *mut BlockJob,
+
+    pub inherits_from: *mut BlockDriverState,
+    pub children: QListHead<BdrvChild>,
+    pub parents: QListHead<BdrvChild>,
+
+    pub options: *mut QDict,
+    pub explicit_options: *mut QDict,
+    pub detect_zeroes: c_int, /* BlockdevDetectZeroesOptions */
+
+    pub backing_blocker: *mut Error,
+
+    pub copy_on_read: c_int,
+
+    pub total_sectors: i64,
+
+    pub before_write_notifiers: NotifierWithReturnList,
+
+    pub in_flight: c_uint,
+    pub serialising_in_flight: c_uint,
+
+    pub wakeup: bool,
+
+    pub wr_highest_offset: u64,
+
+    pub write_threshold_offset: u64,
+    pub write_threshold_notifier: NotifierWithReturn,
+
+    pub io_plugged: c_uint,
+
+    pub tracked_requests: QListHead<BdrvTrackedRequest>,
+    pub flush_queue: CoQueue,
+    pub active_flush_req: bool,
+    pub write_gen: c_uint,
+    pub flushed_gen: c_uint,
+
+    pub dirty_bitmaps: QListHead<BdrvDirtyBitmap>,
+
+    pub enable_write_cache: c_int,
+
+    pub quiesce_counter: c_int,
+}
+
+#[repr(C)]
+pub struct BDRVReopenState {
+    pub bs: *mut BlockDriverState,
+    pub flags: c_int,
+    pub options: *mut QDict,
+    pub explicit_options: *mut QDict,
+    pub opaque: *mut c_void,
+}
+
+#[repr(C)]
+pub struct BdrvCheckResult {
+    pub corruptions: c_int,
+    pub leaks: c_int,
+    pub check_errors: c_int,
+    pub corruptions_fixed: c_int,
+    pub leaks_fixed: c_int,
+    pub image_end_offset: i64,
+    pub bfi: c_int, /* BlockFragInfo */
+}
+
+#[repr(C)]
+pub struct BlockSizes {
+    pub phys: u32,
+    pub log: u32,
+}
+
+#[repr(C)]
+pub struct HDGeometry {
+    pub heads: u32,
+    pub sectors: u32,
+    pub cylinders: u32,
+}
+
+#[repr(C)]
+pub struct BlockLimits {
+    pub request_alignment: u32,
+    pub max_pdiscard: i32,
+    pub pdiscard_alignment: u32,
+    pub max_pwrite_zeroes: i32,
+    pub pwrite_zeroes_alignment: u32,
+    pub opt_transfer: u32,
+    pub max_transfer: u32,
+    pub min_mem_alignment: size_t,
+    pub opt_mem_alignment: size_t,
+    pub max_iov: c_int,
+}
+
+#[repr(C)]
+pub struct BdrvChild {
+    pub bs: *mut BlockDriverState,
+    pub name: *mut c_char,
+    pub role: *const BdrvChildRole,
+    pub opaque: *mut c_void,
+
+    pub perm: u64,
+
+    pub shared_perm: u64,
+
+    pub next: QListEntry<BdrvChild>,
+    pub next_parent: QListEntry<BdrvChild>,
+}
+
+#[repr(C)]
+pub struct BdrvChildRole {
+    pub stay_at_node: bool,
+
+    pub inherit_options: Option<
+            extern fn(child_flags: *mut c_int, child_options: *mut QDict,
+                      parent_flags: c_int, parent_options: *mut QDict)
+        >,
+
+    pub change_media: Option<extern fn(child: *mut BdrvChild, load: bool)>,
+    pub resize: Option<extern fn(child: *mut BdrvChild)>,
+
+    pub get_name: Option<extern fn(child: *mut BdrvChild) -> *const c_char>,
+
+    /* Return value should probably be allocated in the C program */
+    pub get_parent_desc: Option<
+            extern fn(child: *mut BdrvChild) -> *mut c_char
+        >,
+
+    pub drained_begin: Option<extern fn(child: *mut BdrvChild)>,
+    pub drained_end: Option<extern fn(child: *mut BdrvChild)>,
+
+    pub attach: Option<extern fn(child: *mut BdrvChild)>,
+    pub detach: Option<extern fn(child: *mut BdrvChild)>,
+}
+
+#[repr(C)]
+pub struct BdrvAioNotifier {
+    pub attached_aio_context: Option<
+            extern fn(new_context: *mut AioContext, opaque: *mut c_void)
+        >,
+    pub detach_aio_context: Option<extern fn(opaque: *mut c_void)>,
+
+    pub opaque: *mut c_void,
+    pub deleted: bool,
+
+    pub list: QListEntry<BdrvAioNotifier>,
+}
+
+#[repr(C)]
+pub struct BlockDriverInfo {
+    pub cluster_size: c_int,
+    pub vm_state_offset: i64,
+    pub is_dirty: bool,
+    pub unallocated_blocks_are_zero: bool,
+    pub can_write_zeroes_with_unmap: bool,
+    pub needs_compressed_writes: bool,
+}
+
+#[repr(C)]
+pub struct ImageInfoSpecific {
+    pub kind: c_int, /* ImageInfoSpecificKind */
+    pub date: *mut c_void, /* type depends on kind */
+}
+
+#[repr(C)]
+pub struct QEMUIOVector {
+    pub iov: *mut iovec,
+    pub niov: c_int,
+    pub nalloc: c_int,
+    pub size: size_t,
+}
+
+#[repr(C)]
+pub struct iovec {
+    pub iov_base: *mut c_void,
+    pub iov_len: size_t,
+}
+
+#[repr(C)]
+pub struct QEMUSnapshotInfo {
+    pub id_str: [c_char; 128],
+    pub name: [c_char; 256],
+    pub vm_state_size: u64,
+    pub date_sec: u32,
+    pub date_nsec: u32,
+    pub vm_clock_nsec: u64,
+}
+
+#[repr(C)]
+pub struct NotifierWithReturnList {
+    pub notifiers: *mut NotifierWithReturn,
+}
+
+#[repr(C)]
+pub struct NotifierWithReturn {
+    pub notify: extern fn(notifier: *mut NotifierWithReturn, data: *mut c_void)
+                    -> c_int,
+    pub node: QListEntry<NotifierWithReturn>,
+}
+
+#[repr(C)]
+pub struct CoQueue {
+    pub entries: CoroutineQSimpleQHead,
+}
+
+#[repr(C)]
+pub struct CoroutineQSimpleQHead {
+    pub sqh_first: *mut Coroutine,
+    pub sqh_last: *mut *mut Coroutine,
+}
+
+#[repr(C)]
+pub struct QListHead<T> {
+    pub lh_first: *mut T,
+}
+
+#[repr(C)]
+pub struct QListEntry<T> {
+    pub le_next: *mut T,
+    pub le_prev: *mut *mut T,
+}
+
+#[repr(C)]
+pub struct QTailQEntry<T> {
+    pub tqe_next: *mut T,
+    pub tqe_prev: *mut *mut T,
+}
+
+type BlockDriverAmendStatusCB = extern fn(bs: *mut BlockDriverState,
+                                          offset: i64, total_work_size: i64,
+                                          opaque: *mut c_void);
+
+/* Opaque types */
+pub enum AioContext {}
+pub enum BdrvDirtyBitmap {}
+pub enum BdrvOpBlocker {}
+pub enum BdrvTrackedRequest {}
+pub enum BlockReopenQueue {}
+pub enum BlockJob {}
+pub enum Coroutine {}
+pub enum Error {}
+pub enum QDict {}
+pub enum QemuOpts {}
+pub enum QemuOptsList {}
+
+/* Used for deprecated function pointers */
+type DeprecatedFn = extern fn();
diff --git a/block/rust/src/interface/mod.rs b/block/rust/src/interface/mod.rs
new file mode 100644
index 0000000000..8afcbe36c5
--- /dev/null
+++ b/block/rust/src/interface/mod.rs
@@ -0,0 +1,1012 @@
+pub mod c_constants;
+pub mod c_functions;
+pub mod c_structs;
+
+
+use core::intrinsics::transmute;
+use core::marker::Sized;
+pub use core::ops::{Deref,DerefMut};
+use libc;
+use libc::{c_char,c_int,c_void,size_t,EINVAL,EIO,ENOSPC,ENOTSUP,EPERM};
+use self::c_functions::error_setg_internal;
+use std::{mem,ptr,slice};
+use std::cell::RefCell;
+use std::ffi::CString;
+use std::io;
+use std::io::Write;
+use std::marker::PhantomData;
+use std::rc::{Rc,Weak};
+
+
+pub type QDict = *mut c_structs::QDict;
+pub type CBDS = c_structs::BlockDriverState;
+
+
+pub const BDRV_SECTOR_SIZE: u64 = 512u64;
+pub const BDRV_SECTOR_SHIFT: i32 = 9;
+
+
+pub enum IOError {
+    GenericError,
+    NoSpaceLeft,
+    InvalidMetadata,
+    UnsupportedImageFeature,
+}
+
+impl IOError {
+    pub fn to_errno(&self) -> c_int
+    {
+        match *self {
+            IOError::GenericError => -EIO,
+            IOError::NoSpaceLeft => -ENOSPC,
+            IOError::InvalidMetadata => -EIO,
+            IOError::UnsupportedImageFeature => -ENOTSUP,
+        }
+    }
+}
+
+
+pub struct BDSOpaqueLink<T> {
+    pub opaque: Option<Rc<Box<BDSOpaque<T>>>>,
+}
+
+pub struct BDSOpaque<T> {
+    c_obj: *mut CBDS,
+    pub driver_obj: RefCell<T>,
+}
+
+
+/*
+ * Macros for extracting the block driver's opaque BDS from a &mut CBDS
+ *
+ * Note that we have to pass a CBDS to the block driver functions instead of
+ * the opaque BDS itself because a block driver is allowed to do recursive 
calls
+ * (and even if it does not do so actively, the qemu block layer may just do it
+ * anyway). The borrow checker will prevent us from borrowing the opaque BDS in
+ * recursive function invocations, so the functions will have to borrow it only
+ * when needed.
+ */
+#[macro_export]
+macro_rules! let_bds {
+    ($result:ident, $cbds:expr) => (
+        let _bds_opaque = get_bds_opaque_link::<Self>($cbds).unwrap();
+        let mut _driver_obj_ref = _bds_opaque.driver_obj.borrow();
+        let $result = _driver_obj_ref.deref();
+    );
+}
+
+#[macro_export]
+macro_rules! let_mut_bds {
+    ($result:ident, $cbds:expr) => (
+        let _bds_opaque = get_bds_opaque_link::<Self>($cbds).unwrap();
+        let mut _driver_obj_ref = _bds_opaque.driver_obj.borrow_mut();
+        let $result = _driver_obj_ref.deref_mut();
+    );
+}
+
+
+/* Allows you to prepend an error string to an error string on error */
+#[macro_export]
+macro_rules! try_prepend {
+    ($e:expr, $m:expr) => (match $e {
+        Ok(val) => val,
+        Err(err) => return Err(String::from($m) + ": " + err.as_str()),
+    });
+}
+
+
+/* try! that executes a qemu_vfree() on error */
+#[macro_export]
+macro_rules! try_vfree {
+    ($e:expr, $buffer:ident) => (match $e {
+            Ok(ok) => ok,
+            Err(err) => {
+                qemu_vfree($buffer);
+                return Err(err);
+            },
+        });
+}
+
+
+
+pub struct BDSBacklink<T> {
+    pub link: Weak<Box<BDSOpaque<T>>>,
+}
+
+pub struct BDSCommon<T> {
+    backlink: Option<BDSBacklink<T>>,
+}
+
+impl<T> BDSCommon<T> {
+    pub fn new() -> Self
+    {
+        Self {
+            backlink: None,
+        }
+    }
+
+    pub fn set_backlink(&mut self, backlink: BDSBacklink<T>)
+    {
+        self.backlink = Some(backlink);
+    }
+
+    pub fn get_cbds(&self) -> &mut CBDS
+    {
+        let backlink = self.backlink.as_ref().unwrap();
+        let bds_opaque_rc = backlink.link.upgrade();
+        let bds_opaque = Rc::as_ref(bds_opaque_rc.as_ref().unwrap());
+
+        let res = unsafe { &mut *bds_opaque.c_obj };
+        return res;
+    }
+
+    pub fn has_file(&self) -> bool
+    {
+        let cbds = self.get_cbds();
+        !cbds.file.is_null()
+    }
+
+    pub fn file(&self) -> BdrvChild
+    {
+        let cbds = self.get_cbds();
+        BdrvChild { c_ptr: cbds.file }
+    }
+
+    pub fn set_file(&mut self, file: Option<BdrvChild>)
+    {
+        let cbds = self.get_cbds();
+
+        match file {
+            None => cbds.file = ptr::null_mut(),
+            Some(ref child) => cbds.file = child.c_ptr,
+        };
+    }
+
+    pub fn has_backing(&self) -> bool
+    {
+        let cbds = self.get_cbds();
+        !cbds.backing.is_null()
+    }
+
+    pub fn backing(&self) -> BdrvChild
+    {
+        let cbds = self.get_cbds();
+        BdrvChild { c_ptr: cbds.backing }
+    }
+
+    pub fn set_backing(&mut self, backing: Option<BdrvChild>)
+    {
+        let cbds = self.get_cbds();
+
+        match backing {
+            None => cbds.file = ptr::null_mut(),
+            Some(ref child) => cbds.file = child.c_ptr,
+        };
+    }
+}
+
+
+pub trait BlockDriverState where Self: Sized {
+    fn new() -> Self;
+    fn common(&mut self) -> &mut BDSCommon<Self>;
+
+    fn set_backlink(&mut self, backlink: BDSBacklink<Self>)
+    {
+        self.common().set_backlink(backlink);
+    }
+}
+
+pub trait BlockDriverOpen: BlockDriverState {
+    fn bdrv_open(cbds: &mut CBDS, options: QDict, flags: u32)
+        -> Result<(), String>;
+}
+
+pub trait BlockDriverClose: BlockDriverState {
+    fn bdrv_close(cbds: &mut CBDS);
+}
+
+pub trait BlockDriverRead: BlockDriverState {
+    /* iov is ordered backwards so you can pop in order */
+    fn bdrv_co_preadv(cbds: &mut CBDS, offset: u64, bytes: u64,
+                      iov: Vec<&mut [u8]>, flags: u32)
+        -> Result<(), IOError>;
+}
+
+pub trait BlockDriverWrite: BlockDriverState {
+    /* iov is ordered backwards so you can pop in order */
+    fn bdrv_co_pwritev(cbds: &mut CBDS, offset: u64, bytes: u64,
+                       iov: Vec<&[u8]>, flags: u32)
+        -> Result<(), IOError>;
+}
+
+pub trait BlockDriverPerm: BlockDriverState {
+    fn bdrv_check_perm(cbds: &mut CBDS, perm: u64, shared: u64)
+        -> Result<(), String>;
+    fn bdrv_set_perm(cbds: &mut CBDS, perm: u64, shared: u64);
+    fn bdrv_abort_perm_update(cbds: &mut CBDS);
+}
+
+pub trait BlockDriverChildPerm: BlockDriverState {
+    fn bdrv_child_perm(cbds: &mut CBDS, c: Option<&mut BdrvChild>,
+                       role: &c_structs::BdrvChildRole,
+                       parent_perm: u64, parent_shared: u64)
+        -> (u64, u64); /* nperm, nshared */
+}
+
+pub trait BlockDriverInfo: BlockDriverState {
+    fn bdrv_get_info(cbds: &mut CBDS, bdi: &mut c_structs::BlockDriverInfo)
+        -> Result<(), String>;
+}
+
+
+pub struct BlockDriver<T> {
+    c_obj: c_structs::BlockDriver,
+
+    _phantom: PhantomData<T>,
+}
+
+
+pub fn get_bds_opaque_link<'a, T>(bds: *mut CBDS)
+    -> &'a mut BDSOpaqueLink<T>
+{
+    unsafe {
+        let r = transmute::<*mut c_void, *mut BDSOpaqueLink<T>>((*bds).opaque);
+        return &mut *r;
+    }
+}
+
+impl<T> BDSOpaqueLink<T> {
+    pub fn unwrap(&self) -> &BDSOpaque<T>
+    {
+        Rc::as_ref(self.opaque.as_ref().unwrap()).as_ref()
+    }
+}
+
+
+pub struct BdrvChild {
+    c_ptr: *mut c_structs::BdrvChild,
+}
+
+
+impl BdrvChild {
+    pub fn perm(&self) -> u64
+    {
+        unsafe {
+            (*self.c_ptr).perm
+        }
+    }
+
+    pub fn shared(&self) -> u64
+    {
+        unsafe {
+            (*self.c_ptr).shared_perm
+        }
+    }
+
+    pub fn borrow(&self) -> Self
+    {
+        BdrvChild {
+            c_ptr: self.c_ptr
+        }
+    }
+
+    pub fn bdrv_pread(&self, offset: u64, buf: &mut [u8])
+        -> Result<(), String>
+    {
+        let ret = unsafe {
+             c_functions::bdrv_pread(self.c_ptr, offset as i64,
+                                     buf.as_mut_ptr() as *mut c_void,
+                                     buf.len() as c_int)
+        };
+
+        if ret < 0 {
+            Err(strerror(-ret))
+        } else {
+            Ok(())
+        }
+    }
+
+    pub fn bdrv_pwrite(&self, offset: u64, buf: &[u8])
+        -> Result<(), String>
+    {
+        let ret = unsafe {
+            c_functions::bdrv_pwrite(self.c_ptr, offset as i64,
+                                     buf.as_ptr() as *const c_void,
+                                     buf.len() as c_int)
+        };
+
+        if ret < 0 {
+            Err(strerror(-ret))
+        } else {
+            Ok(())
+        }
+    }
+}
+
+
+impl<T: BlockDriverOpen> BlockDriver<T> {
+    extern fn invoke_open(bds: *mut CBDS, options: *mut c_structs::QDict,
+                          flags: c_int, errp: *mut *mut c_structs::Error)
+        -> c_int
+    {
+        let bds_opaque_link = get_bds_opaque_link::<T>(bds);
+
+        assert!(bds_opaque_link.opaque.is_none());
+
+        let weak_bds_opaque = {
+            let rc_bds_opaque = Rc::new(Box::new(BDSOpaque::<T> {
+                    c_obj: bds,
+                    driver_obj: RefCell::new(T::new()),
+                }));
+
+            let weak_link = Rc::downgrade(&rc_bds_opaque);
+            bds_opaque_link.opaque = Some(rc_bds_opaque);
+
+            weak_link
+        };
+
+        {
+            let bds_opaque = bds_opaque_link.unwrap();
+            let mut driver_obj_ref = bds_opaque.driver_obj.borrow_mut();
+            let backlink = BDSBacklink::<T> {
+                link: weak_bds_opaque
+            };
+
+            driver_obj_ref.deref_mut().set_backlink(backlink);
+        }
+
+        let cbds = unsafe { &mut *bds };
+        let res = T::bdrv_open(cbds, options, flags as u32);
+
+        match res {
+            Ok(_) => 0,
+            Err(msg) => {
+                bds_opaque_link.opaque = None;
+                error_set_message(errp, msg);
+
+                -EINVAL
+            }
+        }
+    }
+}
+
+
+impl<T: BlockDriverClose> BlockDriver<T> {
+    extern fn invoke_close(bds: *mut CBDS)
+    {
+        let cbds = unsafe { &mut *bds };
+        T::bdrv_close(cbds);
+
+        get_bds_opaque_link::<T>(bds).opaque = None;
+    }
+}
+
+
+impl<T: BlockDriverRead> BlockDriver<T> {
+    extern fn invoke_co_preadv(bds: *mut CBDS, offset: u64, bytes: u64,
+                               qiov: *mut c_structs::QEMUIOVector, flags: 
c_int)
+        -> c_int
+    {
+        let cbds = unsafe { &mut *bds };
+        let qiov_deref = unsafe { &*qiov };
+
+        let qiov_vecs = unsafe {
+                slice::from_raw_parts(qiov_deref.iov, qiov_deref.niov as usize)
+            };
+
+        let mut iov = Vec::new();
+        /* Push backwards so the driver can pop in the right order */
+        for vec in qiov_vecs.iter().rev() {
+            iov.push(iov_as_mut_byte_slice(vec));
+        }
+
+        let res = T::bdrv_co_preadv(cbds, offset, bytes, iov, flags as u32);
+        match res {
+            Ok(_) => 0,
+            Err(err) => err.to_errno(),
+        }
+    }
+}
+
+
+impl<T: BlockDriverWrite> BlockDriver<T> {
+    extern fn invoke_co_pwritev(bds: *mut CBDS, offset: u64, bytes: u64,
+                                qiov: *mut c_structs::QEMUIOVector, flags: 
c_int)
+        -> c_int
+    {
+        let cbds = unsafe { &mut *bds };
+        let qiov_deref = unsafe { &*qiov };
+
+        let qiov_vecs = unsafe {
+                slice::from_raw_parts(qiov_deref.iov, qiov_deref.niov as usize)
+            };
+
+        let mut iov = Vec::new();
+        /* Push backwards so the driver can pop in the right order */
+        for vec in qiov_vecs.iter().rev() {
+            iov.push(iov_as_byte_slice(vec));
+        }
+
+        let res = T::bdrv_co_pwritev(cbds, offset, bytes, iov, flags as u32);
+        match res {
+            Ok(_) => 0,
+            Err(err) => err.to_errno(),
+        }
+    }
+}
+
+
+impl<T: BlockDriverPerm> BlockDriver<T> {
+    extern fn invoke_check_perm(bds: *mut CBDS, perm: u64, shared: u64,
+                                errp: *mut *mut c_structs::Error)
+        -> c_int
+    {
+        let cbds = unsafe { &mut *bds };
+        let res = T::bdrv_check_perm(cbds, perm, shared);
+        match res {
+            Ok(_) => 0,
+            Err(msg) => {
+                error_set_message(errp, msg);
+                -EPERM
+            }
+        }
+    }
+
+    extern fn invoke_set_perm(bds: *mut CBDS, perm: u64, shared: u64)
+    {
+        let cbds = unsafe { &mut *bds };
+        T::bdrv_set_perm(cbds, perm, shared);
+    }
+
+    extern fn invoke_abort_perm_update(bds: *mut CBDS)
+    {
+        let cbds = unsafe { &mut *bds };
+        T::bdrv_abort_perm_update(cbds);
+    }
+}
+
+
+impl<T: BlockDriverChildPerm> BlockDriver<T> {
+    extern fn invoke_child_perm(bds: *mut CBDS, c: *mut c_structs::BdrvChild,
+                                role: *const c_structs::BdrvChildRole,
+                                parent_perm: u64, parent_shared: u64,
+                                nperm: *mut u64, nshared: *mut u64)
+    {
+        let cbds = unsafe { &mut *bds };
+        let role_deref = unsafe { &*role };
+
+        let res = if c.is_null() {
+                T::bdrv_child_perm(cbds, None, role_deref,
+                                   parent_perm, parent_shared)
+            } else {
+                let mut child = BdrvChild { c_ptr: c };
+                T::bdrv_child_perm(cbds, Some(&mut child), role_deref,
+                                   parent_perm, parent_shared)
+            };
+
+        unsafe {
+            *nperm = res.0;
+            *nshared = res.1;
+        }
+    }
+}
+
+
+impl<T: BlockDriverInfo> BlockDriver<T> {
+    extern fn invoke_get_info(bds: *mut CBDS,
+                              bdi: *mut c_structs::BlockDriverInfo)
+        -> c_int
+    {
+        let cbds = unsafe { &mut *bds };
+        let bdi_deref = unsafe { &mut *bdi };
+
+        let res = T::bdrv_get_info(cbds, bdi_deref);
+        match res {
+            Ok(_) => 0,
+            Err(msg) => {
+                writeln!(&mut io::stderr(), "{}", msg).unwrap();
+                -EIO
+            }
+        }
+    }
+}
+
+
+impl<T: BlockDriverState> BlockDriver<T> {
+    pub fn new(name: String) -> BlockDriver<T>
+    {
+        let instance_size = mem::size_of::<BDSOpaque<T>>();
+        let /*mut*/ bdrv = BlockDriver::<T> {
+            c_obj: c_structs::BlockDriver {
+                format_name: CString::new(name).unwrap().into_raw(),
+                instance_size: instance_size as c_int,
+
+                is_filter: false,
+
+                bdrv_recurse_is_first_non_filter: None,
+
+                bdrv_probe: None,
+                bdrv_probe_device: None,
+
+                bdrv_parse_filename: None,
+                bdrv_needs_filename: false,
+
+                supports_backing: false,
+
+                bdrv_reopen_prepare: None,
+                bdrv_reopen_commit: None,
+                bdrv_reopen_abort: None,
+                bdrv_join_options: None,
+
+                bdrv_open: None,
+                bdrv_file_open: None,
+                bdrv_close: None,
+                bdrv_create: None,
+                bdrv_set_key: None,
+                bdrv_make_empty: None,
+
+                bdrv_refresh_filename: None,
+
+                bdrv_aio_readv: None,
+                bdrv_aio_writev: None,
+                bdrv_aio_flush: None,
+                bdrv_aio_pdiscard: None,
+
+                bdrv_co_readv: None,
+                bdrv_co_preadv: None,
+                bdrv_co_writev: None,
+                bdrv_co_writev_flags: None,
+                bdrv_co_pwritev: None,
+
+                bdrv_co_pwrite_zeroes: None,
+                bdrv_co_pdiscard: None,
+                bdrv_co_get_block_status: None,
+
+                bdrv_invalidate_cache: None,
+                bdrv_inactivate: None,
+
+                bdrv_co_flush: None,
+
+                bdrv_co_flush_to_disk: None,
+
+                bdrv_co_flush_to_os: None,
+
+                protocol_name: ptr::null(),
+                bdrv_truncate: None,
+
+                bdrv_getlength: None,
+                has_variable_length: false,
+                bdrv_get_allocated_file_size: None,
+
+                bdrv_co_pwritev_compressed: None,
+
+                bdrv_snapshot_create: None,
+                bdrv_snapshot_goto: None,
+                bdrv_snapshot_delete: None,
+                bdrv_snapshot_list: None,
+                bdrv_snapshot_load_tmp: None,
+
+                bdrv_get_info: None,
+                bdrv_get_specific_info: None,
+
+                bdrv_save_vmstate: None,
+                bdrv_load_vmstate: None,
+
+                bdrv_change_backing_file: None,
+
+                bdrv_is_inserted: None,
+                bdrv_media_changed: None,
+                bdrv_eject: None,
+                bdrv_lock_medium: None,
+
+                bdrv_aio_ioctl: None,
+                bdrv_co_ioctl: None,
+
+                create_opts: ptr::null_mut(),
+
+                bdrv_check: None,
+
+                bdrv_amend_options: None,
+
+                bdrv_debug_event: None,
+                bdrv_debug_breakpoint: None,
+                bdrv_debug_remove_breakpoint: None,
+                bdrv_debug_resume: None,
+                bdrv_debug_is_suspended: None,
+
+                bdrv_refresh_limits: None,
+
+                bdrv_has_zero_init: None,
+
+                bdrv_detach_aio_context: None,
+
+                bdrv_attach_aio_context: None,
+
+                bdrv_io_plug: None,
+                bdrv_io_unplug: None,
+
+                bdrv_probe_blocksizes: None,
+                bdrv_probe_geometry: None,
+
+                bdrv_drain: None,
+
+                bdrv_add_child: None,
+                bdrv_del_child: None,
+
+                bdrv_check_perm: None,
+                bdrv_set_perm: None,
+                bdrv_abort_perm_update: None,
+
+                bdrv_child_perm: None,
+
+                list: c_structs::QListEntry::<c_structs::BlockDriver> {
+                    le_next: ptr::null_mut(),
+                    le_prev: ptr::null_mut(),
+                },
+            },
+
+            _phantom: PhantomData,
+        };
+
+        /* TODO: Call provides_* automatically
+         * (We cannot do this currently because there is no way to either
+         *  (1) Check whether T implements a trait in an if clause
+         *  (2) Implement provides_* if T does not implement a trait
+         *  (The latter of which is something that Rust is expected to 
implement
+         *   at some point in the future.)) */
+
+        return bdrv;
+    }
+
+    pub fn supports_backing(&mut self)
+    {
+        self.c_obj.supports_backing = true;
+    }
+
+    pub fn has_variable_length(&mut self)
+    {
+        self.c_obj.has_variable_length = true;
+    }
+}
+
+
+impl<T: BlockDriverOpen> BlockDriver<T> {
+    pub fn provides_open(&mut self)
+    {
+        self.c_obj.bdrv_open = Some(BlockDriver::<T>::invoke_open);
+    }
+}
+
+
+impl<T: BlockDriverClose> BlockDriver<T> {
+    pub fn provides_close(&mut self)
+    {
+        self.c_obj.bdrv_close = Some(BlockDriver::<T>::invoke_close);
+    }
+}
+
+
+impl<T: BlockDriverRead> BlockDriver<T> {
+    pub fn provides_read(&mut self)
+    {
+        self.c_obj.bdrv_co_preadv = Some(BlockDriver::<T>::invoke_co_preadv);
+    }
+}
+
+
+impl<T: BlockDriverWrite> BlockDriver<T> {
+    pub fn provides_write(&mut self)
+    {
+        self.c_obj.bdrv_co_pwritev = Some(BlockDriver::<T>::invoke_co_pwritev);
+    }
+}
+
+
+impl<T: BlockDriverPerm> BlockDriver<T> {
+    pub fn provides_perm(&mut self)
+    {
+        self.c_obj.bdrv_check_perm = Some(BlockDriver::<T>::invoke_check_perm);
+        self.c_obj.bdrv_set_perm = Some(BlockDriver::<T>::invoke_set_perm);
+        self.c_obj.bdrv_abort_perm_update =
+            Some(BlockDriver::<T>::invoke_abort_perm_update);
+    }
+}
+
+
+impl<T: BlockDriverChildPerm> BlockDriver<T> {
+    pub fn provides_child_perm(&mut self)
+    {
+        self.c_obj.bdrv_child_perm = Some(BlockDriver::<T>::invoke_child_perm);
+    }
+}
+
+
+impl<T: BlockDriverInfo> BlockDriver<T> {
+    pub fn provides_info(&mut self)
+    {
+        self.c_obj.bdrv_get_info = Some(BlockDriver::<T>::invoke_get_info);
+    }
+}
+
+
+pub fn bdrv_register<T>(bdrv: BlockDriver<T>)
+{
+    /* Box so it doesn't go away */
+    let bdrv_box = Box::new(bdrv);
+
+    unsafe {
+        c_functions::bdrv_register(&mut (*Box::into_raw(bdrv_box)).c_obj);
+    }
+}
+
+
+pub fn bdrv_open_child(filename: Option<String>, options: Option<QDict>,
+                       bdref_key: String, parent: &mut CBDS,
+                       child_role: &c_structs::BdrvChildRole, allow_none: bool)
+    -> Result<BdrvChild, String>
+{
+    let c_filename = match filename {
+        None => ptr::null(),
+        Some(x) => CString::new(x).unwrap().into_raw(),
+    };
+
+    let c_options = match options {
+        None => ptr::null_mut(),
+        Some(x) => x,
+    };
+
+    let c_bdref_key = CString::new(bdref_key).unwrap().into_raw();
+    let c_parent = parent as *mut CBDS;
+    let c_child_role = child_role as *const c_structs::BdrvChildRole;
+
+    let c_allow_none = allow_none;
+
+    unsafe {
+        let mut local_err: *mut c_structs::Error = ptr::null_mut();
+        let c_errp = &mut local_err as *mut *mut c_structs::Error;
+
+        let child = c_functions::bdrv_open_child(c_filename, c_options,
+                                                 c_bdref_key, c_parent,
+                                                 c_child_role, c_allow_none,
+                                                 c_errp);
+
+        if child.is_null() {
+            Err(error_get_string(local_err))
+        } else {
+            Ok(BdrvChild { c_ptr: child })
+        }
+    }
+}
+
+
+pub enum StandardChildRole {
+    File,
+    Format,
+    Backing,
+}
+
+pub fn bdrv_get_standard_child_role(role: StandardChildRole)
+    -> &'static c_structs::BdrvChildRole
+{
+    unsafe {
+        match role {
+            StandardChildRole::File => &c_constants::child_file,
+            StandardChildRole::Format => &c_constants::child_format,
+            StandardChildRole::Backing => &c_constants::child_backing,
+        }
+    }
+}
+
+
+const BLK_PERM_CONSISTENT_READ  : u64 = 0x01u64;
+const BLK_PERM_WRITE            : u64 = 0x02u64;
+const BLK_PERM_WRITE_UNCHANGED  : u64 = 0x04u64;
+const BLK_PERM_RESIZE           : u64 = 0x08u64;
+const BLK_PERM_GRAPH_MOD        : u64 = 0x10u64;
+
+const BLK_PERM_ALL              : u64 = 0x1fu64;
+
+
+pub fn bdrv_filter_default_perms(c: Option<&mut BdrvChild>,
+                                 _: &c_structs::BdrvChildRole,
+                                 perm: u64, shared: u64)
+    -> (u64, u64)
+{
+    let default_perm_passthrough = BLK_PERM_CONSISTENT_READ
+                                   | BLK_PERM_WRITE
+                                   | BLK_PERM_WRITE_UNCHANGED
+                                   | BLK_PERM_RESIZE;
+    let default_perm_unchanged = BLK_PERM_ALL & !default_perm_passthrough;
+
+    if c.is_none() {
+        (perm & default_perm_passthrough,
+         (shared & default_perm_passthrough) | default_perm_unchanged)
+    } else {
+        let child = c.unwrap();
+
+        ((perm & default_perm_passthrough) |
+         (child.perm() & default_perm_unchanged),
+
+         (shared & default_perm_passthrough) |
+         (child.shared() & default_perm_unchanged))
+    }
+}
+
+
+pub fn bdrv_format_default_perms(c: Option<&mut BdrvChild>,
+                                 role: &c_structs::BdrvChildRole,
+                                 perm: u64, shared: u64, is_read_only: bool)
+    -> (u64, u64)
+{
+    let backing_role =
+        bdrv_get_standard_child_role(StandardChildRole::Backing);
+
+    let mut p = perm;
+    let mut s = shared;
+
+    if role as *const c_structs::BdrvChildRole
+        == backing_role as *const c_structs::BdrvChildRole
+    {
+        p &= BLK_PERM_CONSISTENT_READ;
+
+        if (s & BLK_PERM_WRITE) != 0 {
+            s = BLK_PERM_WRITE | BLK_PERM_RESIZE;
+        } else {
+            s = 0;
+        }
+
+        s |= BLK_PERM_CONSISTENT_READ | BLK_PERM_GRAPH_MOD |
+             BLK_PERM_WRITE_UNCHANGED;
+    } else {
+        let filter = bdrv_filter_default_perms(c, role, p, s);
+        p = filter.0;
+        s = filter.1;
+
+        if !is_read_only {
+            p |= BLK_PERM_WRITE | BLK_PERM_RESIZE;
+        }
+
+        p |= BLK_PERM_CONSISTENT_READ;
+        s &= !(BLK_PERM_WRITE | BLK_PERM_RESIZE);
+    }
+
+    (p, s)
+}
+
+
+pub fn bdrv_is_read_only(bds: *mut CBDS) -> bool
+{
+    unsafe {
+        c_functions::bdrv_is_read_only(bds)
+    }
+}
+
+
+fn error_get_string(err: *mut c_structs::Error) -> String
+{
+    unsafe {
+        let msg = c_functions::error_get_pretty(err);
+        let dmsg = c_functions::g_strdup(msg);
+
+        CString::from_raw(dmsg).into_string().unwrap()
+    }
+}
+
+
+fn error_set_message(errp: *mut *mut c_structs::Error, msg: String)
+{
+    let file = CString::new("<FILE>").unwrap();
+    let func = CString::new("<FUNC>").unwrap();
+    let format = CString::new("%.*s").unwrap();
+
+    unsafe {
+        error_setg_internal(errp, file.as_ptr(), -1, func.as_ptr(),
+                            format.as_ptr(),
+                            msg.len() as c_int,
+                            msg.as_ptr() as *const c_char);
+    }
+}
+
+
+fn strerror(errno: c_int) -> String
+{
+    unsafe {
+        let msg = libc::strerror(errno);
+        let dmsg = c_functions::g_strdup(msg);
+
+        CString::from_raw(dmsg).into_string().unwrap()
+    }
+}
+
+
+/* Attention: The content of the slice is undefined!
+ * (Also: Remember that the slice will not be automatically freed; you have to
+ *  manually call qemu_vfree() for that.) */
+pub fn qemu_blockalign(bds: *mut CBDS, size: usize) -> &'static mut [u8]
+{
+    unsafe {
+        let p = c_functions::qemu_blockalign(bds, size as size_t);
+        slice::from_raw_parts_mut(p as *mut u8, size)
+    }
+}
+
+
+pub fn qemu_vfree(mem: &mut [u8])
+{
+    unsafe {
+        c_functions::qemu_vfree(mem.as_mut_ptr() as *mut c_void);
+    }
+}
+
+
+pub fn object_as_mut_byte_slice<T>(obj: &mut T) -> &mut [u8]
+{
+    unsafe {
+        let p = obj as *mut T;
+        slice::from_raw_parts_mut(p as *mut u8, mem::size_of::<T>())
+    }
+}
+
+
+pub fn object_as_byte_slice<T>(obj: &T) -> &[u8]
+{
+    unsafe {
+        let p = obj as *const T;
+        slice::from_raw_parts(p as *const u8, mem::size_of::<T>())
+    }
+}
+
+
+pub fn vec_as_mut_byte_slice<T>(obj: &mut Vec<T>) -> &mut [u8]
+{
+    unsafe {
+        let p = &mut obj[0] as *mut T;
+        slice::from_raw_parts_mut(p as *mut u8, obj.len() * 
mem::size_of::<T>())
+    }
+}
+
+
+pub fn slice_as_mut_byte_slice<T>(obj: &mut [T]) -> &mut [u8]
+{
+    unsafe {
+        slice::from_raw_parts_mut(obj.as_mut_ptr() as *mut u8,
+                                  obj.len() * mem::size_of::<T>())
+    }
+}
+
+
+pub fn iov_as_mut_byte_slice(obj: &c_structs::iovec) -> &mut [u8]
+{
+    unsafe {
+        slice::from_raw_parts_mut(obj.iov_base as *mut u8, obj.iov_len)
+    }
+}
+
+
+pub fn iov_as_byte_slice(obj: &c_structs::iovec) -> &[u8]
+{
+    unsafe {
+        slice::from_raw_parts(obj.iov_base as *const u8, obj.iov_len)
+    }
+}
+
+
+pub fn zero_byte_slice(slice: &mut [u8])
+{
+    unsafe {
+        libc::memset(slice.as_mut_ptr() as *mut c_void, 0, slice.len());
+    }
+}
+
+
+pub fn copy_into_byte_slice(dest: &mut [u8], offset: usize, src: &[u8])
+{
+    assert!(dest.len() >= offset + src.len());
+    unsafe {
+        let ptr = dest.as_mut_ptr();
+        ptr.offset(offset as isize);
+
+        libc::memcpy(ptr as *mut c_void, src.as_ptr() as *const c_void,
+                     src.len());
+    }
+}
diff --git a/block/rust/src/lib.rs b/block/rust/src/lib.rs
new file mode 100644
index 0000000000..2aa2f365ba
--- /dev/null
+++ b/block/rust/src/lib.rs
@@ -0,0 +1,9 @@
+/* Rust cannot not complain about unused public interfaces, which is rather
+ * annoying */
+#![allow(dead_code)]
+
+extern crate core;
+extern crate libc;
+
+#[macro_use]
+mod interface;
-- 
2.12.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]