Implemented locking commands and fixed a couple other small problems

This commit is contained in:
Bruce Leidl 2019-09-21 20:45:15 -04:00
parent ffe02a3fc2
commit dc2a7f7a1f
3 changed files with 182 additions and 9 deletions

View File

@ -1,8 +1,9 @@
use std::cell::{RefCell, RefMut};
use std::cell::{RefCell, RefMut, Cell};
use std::collections::BTreeMap;
use std::{io, fmt};
use std::path::{Path, PathBuf, Component};
use std::fs::{Metadata, File};
use std::os::unix::io::{RawFd,AsRawFd};
use std::os::linux::fs::MetadataExt;
use std::os::unix::fs::FileExt;
@ -12,7 +13,6 @@ use crate::devices::virtio_9p::{
use std::io::{Cursor, SeekFrom, Seek, Read};
use std::sync::{RwLock, Arc};
pub const P9_DOTL_RDONLY: u32 = 0o00000000;
pub const P9_DOTL_WRONLY: u32 = 0o00000001;
pub const P9_DOTL_RDWR: u32 = 0o00000002;
@ -37,6 +37,21 @@ pub const P9_QTFILE: u8 = 0x00;
pub const P9_QTSYMLINK: u8 = 0x02;
pub const P9_QTDIR: u8 = 0x80;
const P9_LOCK_SUCCESS: u8 = 0;
const P9_LOCK_BLOCKED: u8 =1;
const P9_LOCK_ERROR: u8 = 2;
const P9_LOCK_TYPE_RDLCK: u8 = 0;
const P9_LOCK_TYPE_WRLCK: u8 = 1;
const P9_LOCK_TYPE_UNLCK: u8 = 2;
#[derive(PartialEq,Copy,Clone)]
enum LockType {
LockUn,
LockSh,
LockEx,
}
#[derive(Clone)]
pub struct Buffer<T: AsRef<[u8]>>(Arc<RwLock<Cursor<T>>>);
impl <T: AsRef<[u8]>> Buffer <T> {
@ -61,21 +76,35 @@ enum FileObject {
NotAFile,
}
impl FileObject {
fn fd(&self) -> Option<RawFd> {
match self {
FileObject::File(file) => Some(file.as_raw_fd()),
_ => None,
}
}
}
pub struct P9File {
file: FileObject,
lock: Cell<LockType>,
}
impl P9File {
fn new(file: FileObject) -> Self {
P9File { file, lock: Cell::new(LockType::LockUn) }
}
pub fn new_not_a_file() -> Self {
P9File { file: FileObject::NotAFile }
Self::new(FileObject::NotAFile)
}
pub fn from_file(file: File) -> Self {
P9File { file: FileObject::File(file) }
Self::new(FileObject::File(file))
}
pub fn from_buffer(buffer: Buffer<&'static [u8]>) -> Self {
P9File { file: FileObject::BufferFile(buffer) }
Self::new(FileObject::BufferFile(buffer))
}
pub fn sync_all(&self) -> io::Result<()> {
@ -84,6 +113,7 @@ impl P9File {
_ => Ok(()),
}
}
pub fn sync_data(&self) -> io::Result<()> {
match self.file {
FileObject::File(ref f) => f.sync_data(),
@ -106,6 +136,99 @@ impl P9File {
FileObject::NotAFile => Ok(0),
}
}
fn map_locktype(ltype: u8) -> LockType {
match ltype {
P9_LOCK_TYPE_UNLCK => LockType::LockUn,
P9_LOCK_TYPE_RDLCK => LockType::LockSh,
P9_LOCK_TYPE_WRLCK => LockType::LockEx,
_ => LockType::LockUn,
}
}
fn errno() -> i32 {
unsafe { *libc::__errno_location() }
}
fn raw_flock(fd: RawFd, op: i32) -> u8 {
unsafe {
if libc::flock(fd, op) == -1 {
if Self::errno() == libc::EWOULDBLOCK {
P9_LOCK_BLOCKED
} else {
P9_LOCK_ERROR
}
} else {
P9_LOCK_SUCCESS
}
}
}
pub fn flock(&self, ltype: u8) -> io::Result<u8> {
let fd = match self.file.fd() {
Some(fd) => fd,
None => {
self.lock.set(Self::map_locktype(ltype));
return Ok(P9_LOCK_SUCCESS);
}
};
match ltype {
P9_LOCK_TYPE_UNLCK => {
let status = Self::raw_flock(fd, libc::LOCK_UN);
if status == P9_LOCK_SUCCESS {
self.lock.set(LockType::LockUn);
}
Ok(status)
}
P9_LOCK_TYPE_WRLCK => {
let status = Self::raw_flock(fd, libc::LOCK_EX|libc::LOCK_NB);
if status == P9_LOCK_SUCCESS {
self.lock.set(LockType::LockEx);
}
Ok(status)
}
P9_LOCK_TYPE_RDLCK => {
let status = Self::raw_flock(fd, libc::LOCK_SH|libc::LOCK_NB);
if status == P9_LOCK_SUCCESS {
self.lock.set(LockType::LockSh);
}
Ok(status)
}
_ => system_error(libc::EINVAL),
}
}
pub fn getlock(&self, ltype: u8) -> io::Result<u8> {
let fd = match self.file.fd() {
Some(fd) => fd,
None => {
return Ok(P9_LOCK_TYPE_UNLCK);
}
};
match ltype {
P9_LOCK_TYPE_RDLCK => {
if self.lock.get() == LockType::LockUn {
match Self::raw_flock(fd, libc::LOCK_NB|libc::LOCK_SH) {
P9_LOCK_SUCCESS => { Self::raw_flock(fd, libc::LOCK_UN); }
_ => return Ok(P9_LOCK_TYPE_WRLCK),
}
}
}
P9_LOCK_TYPE_WRLCK => {
if self.lock.get() == LockType::LockUn {
match Self::raw_flock(fd, libc::LOCK_NB|libc::LOCK_EX) {
P9_LOCK_SUCCESS => { Self::raw_flock(fd, libc::LOCK_UN); },
_ => return Ok(P9_LOCK_TYPE_WRLCK),
}
}
}
_ => {}
}
Ok(P9_LOCK_TYPE_UNLCK)
}
}
#[derive(Copy,Clone)]

View File

@ -89,7 +89,6 @@ impl FileSystem {
}
fn metadata(&self, path: &Path) -> io::Result<Metadata> {
let path = self.canonicalize(path)?;
path.symlink_metadata()
}
@ -246,7 +245,7 @@ impl FileSystemOps for FileSystem {
}
fn readlink(&self, path: &Path) -> io::Result<OsString> {
let path = self.canonicalize(path)?;
let path = self.canonicalize_parent(path)?;
fs::read_link(&path).map(|pbuf| pbuf.into_os_string())
}

View File

@ -35,6 +35,9 @@ const P9_TWRITE: u8 = 118;
const P9_TCLUNK: u8 = 120;
const P9_REMOVE: u8 = 122;
const P9_LOCK_FLAGS_BLOCK: u32 = 1;
pub struct Server<T: FileSystemOps> {
root: PathBuf,
debug: bool,
@ -110,8 +113,8 @@ impl <T: FileSystemOps> Server<T> {
P9_TXATTRCREATE => self.p9_unsupported(pp)?,
P9_TREADDIR => self.p9_readdir(pp)?,
P9_TFSYNC => self.p9_fsync(pp)?,
P9_TLOCK => self.p9_unsupported(pp)?,
P9_TGETLOCK => self.p9_unsupported(pp)?,
P9_TLOCK => self.p9_lock(pp)?,
P9_TGETLOCK => self.p9_getlock(pp)?,
P9_TUNLINKAT => self.p9_unlinkat(pp)?,
P9_TLINK => self.p9_link(pp)?,
P9_TMKDIR=> self.p9_mkdir(pp)?,
@ -401,6 +404,54 @@ impl <T: FileSystemOps> Server<T> {
pp.write_done()
}
fn p9_lock_args(&self, pp: &mut PduParser) -> io::Result<(&Fid<T>,u8,u32)> {
let fid = self.read_fid(pp)?;
let ltype = pp.r8()?;
let flags = pp.r32()?;
let _ = pp.r64()?;
let _ = pp.r64()?;
let _ = pp.r32()?;
let _ = pp.read_string()?;
pp.read_done()?;
Ok((fid, ltype, flags))
}
fn p9_lock(&mut self, pp: &mut PduParser) -> io::Result<()> {
let (fid, ltype,flags)= self.p9_lock_args(pp)?;
if flags & !P9_LOCK_FLAGS_BLOCK != 0 {
return system_error(libc::EINVAL);
}
let file = fid.file()?;
let status = file.flock(ltype)?;
pp.w8(status)?;
pp.write_done()
}
fn p9_getlock_args(&mut self, pp: &mut PduParser) -> io::Result<(&Fid<T>, u8, u64, u64, u32, String)> {
let fid = self.read_fid(pp)?;
let ltype = pp.r8()?;
let start = pp.r64()?;
let length= pp.r64()?;
let pid = pp.r32()?;
let client_id = pp.read_string()?;
pp.read_done()?;
Ok((fid, ltype, start, length, pid, client_id))
}
fn p9_getlock(&mut self, pp: &mut PduParser) -> io::Result<()> {
let (fid, ltype,start,length, pid, client_id) = self.p9_getlock_args(pp)?;
let file = fid.file()?;
let rtype = file.getlock(ltype)?;
pp.w8(rtype)?;
pp.w64(start)?;
pp.w64(length)?;
pp.w32(pid)?;
pp.write_string(&client_id)?;
pp.write_done()
}
fn p9_unlinkat_args(&self, pp: &mut PduParser) -> io::Result<(PathBuf, u32)> {
let path = self.read_new_path(pp)?;
let flags = pp.r32()?;