Skip to content
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

Fuse is waiting #4

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ path = "src/lib.rs"

[features]
rust-mount = []
fs-is-waiting = []
60 changes: 58 additions & 2 deletions src/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,15 @@ pub struct Channel {

use fuse::fuse_mount_compat25;

#[cfg(feature="fs-is-waiting")]
use errno::errno;
#[cfg(feature="fs-is-waiting")]
use fuse::fuse_in_header;
#[cfg(feature="fs-is-waiting")]
use std::mem;
#[cfg(feature="fs-is-waiting")]
use libc::{fcntl, F_GETFL, F_SETFL, O_NONBLOCK};

impl Channel {
/// Create a new communication channel to the kernel driver by mounting the
/// given path. The kernel driver will delegate filesystem operations of
Expand All @@ -51,13 +60,47 @@ impl Channel {
&self.mountpoint
}

#[cfg(feature="fs-is-waiting")]
pub fn receive_err(&self, buffer: &mut Vec<u8>) -> io::Result<()> {
let response = fuse_in_header {
len: 28,
opcode: 39,
unique: 0,
nodeid: 0,
uid: 0,
gid: 0,
pid: 0,
padding: 0
};
let byte_response: [u8; 40] = unsafe { mem::transmute(response) };

match errno().0 {
libc::EAGAIN => {
// this is u32, think about endian
unsafe { buffer.set_len(0) };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use buffer.clear() instead, which is safe !

buffer.extend(byte_response.iter().clone());
Ok(())
}
_ => {
Err(io::Error::last_os_error())
}
}
}

#[cfg(not(feature="fs-is-waiting"))]
pub fn receive_err(&self, _: &mut Vec<u8>) -> io::Result<()> {
Err(io::Error::last_os_error())
}

/// Receives data up to the capacity of the given buffer (can block).
pub fn receive (&self, buffer: &mut Vec<u8>) -> io::Result<()> {
pub fn receive (&self, buffer: &mut Vec<u8>) -> io::Result<()> {
let rc = unsafe { libc::read(self.fd, buffer.as_ptr() as *mut c_void, buffer.capacity() as size_t) };
if rc < 0 {
Err(io::Error::last_os_error())
self.receive_err(buffer)
} else {
unsafe { buffer.set_len(rc as usize); }
#[cfg(feature="fs-is-waiting")]
unsafe { fcntl(self.fd, F_SETFL, O_NONBLOCK); }
Ok(())
}
}
Expand Down Expand Up @@ -111,6 +154,19 @@ impl ReplySender for ChannelSender {
error!("Failed to send FUSE reply: {}", err);
}
}

#[cfg(feature="fs-is-waiting")]
fn set_blocking(&self, blocking: bool) {
unsafe {
let mut flags = fcntl(self.fd, F_GETFL, 0);
if blocking {
flags ^= O_NONBLOCK;
} else {
flags |= O_NONBLOCK;
}
fcntl(self.fd, F_SETFL, flags);
}
}
}

/// Unmount an arbitrary mount point
Expand Down
4 changes: 4 additions & 0 deletions src/fuse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ pub enum fuse_opcode {
FUSE_INTERRUPT = 36,
FUSE_BMAP = 37,
FUSE_DESTROY = 38,
#[cfg(feature="fs-is-waiting")]
FUSE_WAITING = 39,
#[cfg(target_os = "macos")]
FUSE_SETVOLNAME = 61, // OS X only
#[cfg(target_os = "macos")]
Expand Down Expand Up @@ -207,6 +209,8 @@ impl fuse_opcode {
36 => Some(fuse_opcode::FUSE_INTERRUPT),
37 => Some(fuse_opcode::FUSE_BMAP),
38 => Some(fuse_opcode::FUSE_DESTROY),
#[cfg(feature = "fs-is-waiting")]
39 => Some(fuse_opcode::FUSE_WAITING),
#[cfg(target_os = "macos")]
61 => Some(fuse_opcode::FUSE_SETVOLNAME),
#[cfg(target_os = "macos")]
Expand Down
10 changes: 9 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#![warn(missing_docs, bad_style, unused, unused_extern_crates, unused_import_braces, unused_qualifications, missing_debug_implementations)]

extern crate libc;
#[cfg(feature="rust-mount")]
#[cfg(any(feature="rust-mount", feature="fs-is-waiting"))]
extern crate errno;
#[cfg(feature="rust-mount")]
extern crate sendfd;
Expand All @@ -31,6 +31,8 @@ pub use fuse::FUSE_ROOT_ID;
pub use fuse::consts;
pub use reply::{Reply, ReplyEmpty, ReplyData, ReplyEntry, ReplyAttr, ReplyOpen};
pub use reply::{ReplyWrite, ReplyStatfs, ReplyCreate, ReplyLock, ReplyBmap, ReplyDirectory};
#[cfg(feature="fs-is-waiting")]
pub use reply::ReplyWaiting;
pub use reply::ReplyXattr;
#[cfg(target_os = "macos")]
pub use reply::ReplyXTimes;
Expand Down Expand Up @@ -358,6 +360,12 @@ pub trait Filesystem {
reply.error(ENOSYS);
}

/// Is waiting is called each time fuse kernel doesn't send request
/// If waiting return true, channel will became blocking untill next fuse request
#[cfg(feature = "fs-is-waiting")]
fn is_waiting(&mut self, _req: &Request, reply: ReplyWaiting) {
reply.waiting(true);
}
/// OS X only: Rename the volume. Set fuse_init_out.flags during init to
/// FUSE_VOL_RENAME to enable
#[cfg(target_os = "macos")]
Expand Down
26 changes: 26 additions & 0 deletions src/reply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ use {FileType, FileAttr};
pub trait ReplySender: Send + 'static {
/// Send data.
fn send(&self, data: &[&[u8]]);
#[cfg(feature="fs-is-waiting")]
fn set_blocking(&self, blocking: bool);
}

impl fmt::Debug for Box<ReplySender> {
Expand Down Expand Up @@ -526,6 +528,30 @@ impl ReplyBmap {
}
}

///
/// Waiting reply
///
#[cfg(feature="fs-is-waiting")]
#[derive(Debug)]
pub struct ReplyWaiting {
sender: Box<ReplySender>
}

#[cfg(feature="fs-is-waiting")]
impl Reply for ReplyWaiting {
fn new<S: ReplySender> (_: u64, sender: S) -> ReplyWaiting {
ReplyWaiting { sender: Box::new(sender) }
}
}

#[cfg(feature="fs-is-waiting")]
impl ReplyWaiting {
/// Reply to a request with nothing
pub fn waiting (self, blocking: bool) {
self.sender.set_blocking(blocking);
}
}

///
/// Directory reply
///
Expand Down
5 changes: 5 additions & 0 deletions src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,11 @@ impl<'a> Request<'a> {
debug!("BMAP({}) ino {:#018x}, blocksize {}, ids {}", self.header.unique, self.header.nodeid, arg.blocksize, arg.block);
se.filesystem.bmap(self, self.header.nodeid, arg.blocksize, arg.block, self.reply());
},
#[cfg(feature="fs-is-waiting")]
FUSE_WAITING => {
debug!("WAITING({}) ino {:#018x}", self.header.unique, self.header.nodeid);
se.filesystem.is_waiting(self, self.reply());
},
#[cfg(target_os = "macos")]
FUSE_SETVOLNAME => { // OS X only
let name = data.fetch_str();
Expand Down