Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Robin Randhawa
redoxfs
Commits
e9a7181e
Commit
e9a7181e
authored
Jun 18, 2018
by
Jeremy Soller
Browse files
Merge branch 'master' into 'master'
fmap support See merge request
redox-os/redoxfs!35
parents
a345132e
8c57fd95
Changes
3
Hide whitespace changes
Inline
Side-by-side
src/lib.rs
View file @
e9a7181e
#![crate_name=
"redoxfs"
]
#![crate_type=
"lib"
]
#![deny(warnings)]
//
#![deny(warnings)]
extern
crate
syscall
;
extern
crate
uuid
;
...
...
src/mount/redox/resource.rs
View file @
e9a7181e
...
...
@@ -2,12 +2,13 @@ use std::cmp::{min, max};
use
std
::
time
::{
SystemTime
,
UNIX_EPOCH
};
use
syscall
::
data
::
TimeSpec
;
use
syscall
::
error
::{
Error
,
Result
,
EBADF
,
EINVAL
,
EISDIR
,
EPERM
};
use
syscall
::
error
::{
Error
,
Result
,
EBADF
,
EBUSY
,
EINVAL
,
EISDIR
,
EPERM
};
use
syscall
::
flag
::{
O_ACCMODE
,
O_RDONLY
,
O_WRONLY
,
O_RDWR
,
F_GETFL
,
F_SETFL
,
MODE_PERM
};
use
syscall
::{
Stat
,
SEEK_SET
,
SEEK_CUR
,
SEEK_END
};
use
disk
::
Disk
;
use
filesystem
::
FileSystem
;
use
super
::
scheme
::{
Fmaps
,
FmapKey
,
FmapValue
};
pub
trait
Resource
<
D
:
Disk
>
{
fn
block
(
&
self
)
->
u64
;
...
...
@@ -15,12 +16,14 @@ pub trait Resource<D: Disk> {
fn
read
(
&
mut
self
,
buf
:
&
mut
[
u8
],
fs
:
&
mut
FileSystem
<
D
>
)
->
Result
<
usize
>
;
fn
write
(
&
mut
self
,
buf
:
&
[
u8
],
fs
:
&
mut
FileSystem
<
D
>
)
->
Result
<
usize
>
;
fn
seek
(
&
mut
self
,
offset
:
usize
,
whence
:
usize
,
fs
:
&
mut
FileSystem
<
D
>
)
->
Result
<
usize
>
;
fn
fmap
(
&
mut
self
,
offset
:
usize
,
size
:
usize
,
maps
:
&
mut
Fmaps
,
fs
:
&
mut
FileSystem
<
D
>
)
->
Result
<
usize
>
;
fn
funmap
(
&
mut
self
,
maps
:
&
mut
Fmaps
,
fs
:
&
mut
FileSystem
<
D
>
)
->
Result
<
usize
>
;
fn
fchmod
(
&
mut
self
,
mode
:
u16
,
fs
:
&
mut
FileSystem
<
D
>
)
->
Result
<
usize
>
;
fn
fchown
(
&
mut
self
,
uid
:
u32
,
gid
:
u32
,
fs
:
&
mut
FileSystem
<
D
>
)
->
Result
<
usize
>
;
fn
fcntl
(
&
mut
self
,
cmd
:
usize
,
arg
:
usize
)
->
Result
<
usize
>
;
fn
path
(
&
self
,
buf
:
&
mut
[
u8
])
->
Result
<
usize
>
;
fn
stat
(
&
self
,
_stat
:
&
mut
Stat
,
fs
:
&
mut
FileSystem
<
D
>
)
->
Result
<
usize
>
;
fn
sync
(
&
mut
self
)
->
Result
<
usize
>
;
fn
sync
(
&
mut
self
,
maps
:
&
mut
Fmaps
,
fs
:
&
mut
FileSystem
<
D
>
)
->
Result
<
usize
>
;
fn
truncate
(
&
mut
self
,
len
:
usize
,
fs
:
&
mut
FileSystem
<
D
>
)
->
Result
<
usize
>
;
fn
utimens
(
&
mut
self
,
times
:
&
[
TimeSpec
],
fs
:
&
mut
FileSystem
<
D
>
)
->
Result
<
usize
>
;
}
...
...
@@ -87,6 +90,13 @@ impl<D: Disk> Resource<D> for DirResource {
Ok
(
self
.seek
)
}
fn
fmap
(
&
mut
self
,
_offset
:
usize
,
_size
:
usize
,
_maps
:
&
mut
Fmaps
,
_fs
:
&
mut
FileSystem
<
D
>
)
->
Result
<
usize
>
{
Err
(
Error
::
new
(
EBADF
))
}
fn
funmap
(
&
mut
self
,
_maps
:
&
mut
Fmaps
,
_fs
:
&
mut
FileSystem
<
D
>
)
->
Result
<
usize
>
{
Err
(
Error
::
new
(
EBADF
))
}
fn
fchmod
(
&
mut
self
,
mode
:
u16
,
fs
:
&
mut
FileSystem
<
D
>
)
->
Result
<
usize
>
{
let
mut
node
=
fs
.node
(
self
.block
)
?
;
...
...
@@ -158,7 +168,7 @@ impl<D: Disk> Resource<D> for DirResource {
Ok
(
0
)
}
fn
sync
(
&
mut
self
)
->
Result
<
usize
>
{
fn
sync
(
&
mut
self
,
_maps
:
&
mut
Fmaps
,
_fs
:
&
mut
FileSystem
<
D
>
)
->
Result
<
usize
>
{
Err
(
Error
::
new
(
EBADF
))
}
...
...
@@ -177,6 +187,7 @@ pub struct FileResource {
flags
:
usize
,
seek
:
u64
,
uid
:
u32
,
fmap
:
Option
<
(
usize
,
FmapKey
)
>
}
impl
FileResource
{
...
...
@@ -187,8 +198,31 @@ impl FileResource {
flags
:
flags
,
seek
:
seek
,
uid
:
uid
,
fmap
:
None
}
}
fn
sync_fmap
<
D
:
Disk
>
(
&
mut
self
,
maps
:
&
mut
Fmaps
,
fs
:
&
mut
FileSystem
<
D
>
)
->
Result
<
()
>
{
if
let
Some
((
i
,
key_exact
))
=
self
.fmap
.as_ref
()
{
let
(
_
,
value
)
=
maps
.index
(
*
i
)
.as_mut
()
.expect
(
"mapping dropped while still referenced"
);
// Minimum out of our size and the original file size
let
actual_size
=
value
.actual_size
.min
(
key_exact
.size
);
let
mut
count
=
0
;
while
count
<
actual_size
{
let
mtime
=
SystemTime
::
now
()
.duration_since
(
UNIX_EPOCH
)
.unwrap
();
match
fs
.write_node
(
self
.block
,
key_exact
.offset
as
u64
+
count
as
u64
,
&
value
.buffer
[
count
..
actual_size
],
mtime
.as_secs
(),
mtime
.subsec_nanos
())
?
{
0
=>
{
eprintln!
(
"Fmap failed to write whole buffer, encountered EOF early."
);
break
;
}
n
=>
count
+=
n
,
}
}
}
Ok
(())
}
}
impl
<
D
:
Disk
>
Resource
<
D
>
for
FileResource
{
...
...
@@ -203,6 +237,7 @@ impl<D: Disk> Resource<D> for FileResource {
flags
:
self
.flags
,
seek
:
self
.seek
,
uid
:
self
.uid
,
fmap
:
None
}))
}
...
...
@@ -240,6 +275,71 @@ impl<D: Disk> Resource<D> for FileResource {
Ok
(
self
.seek
as
usize
)
}
fn
fmap
(
&
mut
self
,
offset
:
usize
,
size
:
usize
,
maps
:
&
mut
Fmaps
,
fs
:
&
mut
FileSystem
<
D
>
)
->
Result
<
usize
>
{
if
self
.flags
&
O_ACCMODE
==
O_RDWR
{
let
key_exact
=
FmapKey
{
block
:
self
.block
,
offset
,
size
};
let
i
=
match
maps
.find_compatible
(
&
key_exact
)
{
Ok
((
i
,
(
key_existing
,
value
)))
=>
{
value
.refcount
+=
1
;
self
.fmap
=
Some
((
i
,
key_exact
));
return
Ok
(
value
.buffer
.as_ptr
()
as
usize
+
(
key_exact
.offset
-
key_existing
.offset
))
},
Err
(
None
)
=>
{
// This is bad!
// We reached the limit of maps, and we can't reallocate
// because that would invalidate stuff.
// Sorry, nothing personal :(
return
Err
(
Error
::
new
(
EBUSY
))
},
Err
(
Some
(
i
))
=>
{
// Can't do stuff in here because lifetime issues
i
}
};
let
key_round
=
key_exact
.round
();
let
mut
content
=
vec!
[
0
;
key_round
.size
];
let
mut
count
=
0
;
while
count
<
key_round
.size
{
match
fs
.read_node
(
self
.block
,
key_round
.offset
as
u64
+
count
as
u64
,
&
mut
content
[
count
..
])
?
{
0
=>
break
,
n
=>
count
+=
n
}
}
let
value
=
maps
.insert
(
i
,
key_round
,
FmapValue
{
buffer
:
content
,
actual_size
:
count
,
refcount
:
1
});
self
.fmap
=
Some
((
i
,
key_exact
));
Ok
(
value
.buffer
.as_ptr
()
as
usize
+
(
key_exact
.offset
-
key_round
.offset
))
}
else
{
Err
(
Error
::
new
(
EBADF
))
}
}
fn
funmap
(
&
mut
self
,
maps
:
&
mut
Fmaps
,
fs
:
&
mut
FileSystem
<
D
>
)
->
Result
<
usize
>
{
self
.sync_fmap
(
maps
,
fs
)
?
;
if
let
Some
((
i
,
_
))
=
self
.fmap
.as_ref
()
{
let
value
=
maps
.index
(
*
i
);
let
clear
=
{
let
(
_
,
value
)
=
value
.as_mut
()
.expect
(
"mapping dropped while still referenced"
);
value
.refcount
-=
1
;
value
.refcount
==
0
};
if
clear
{
*
value
=
None
;
}
}
Ok
(
0
)
}
fn
fchmod
(
&
mut
self
,
mode
:
u16
,
fs
:
&
mut
FileSystem
<
D
>
)
->
Result
<
usize
>
{
let
mut
node
=
fs
.node
(
self
.block
)
?
;
...
...
@@ -318,7 +418,8 @@ impl<D: Disk> Resource<D> for FileResource {
Ok
(
0
)
}
fn
sync
(
&
mut
self
)
->
Result
<
usize
>
{
fn
sync
(
&
mut
self
,
maps
:
&
mut
Fmaps
,
fs
:
&
mut
FileSystem
<
D
>
)
->
Result
<
usize
>
{
self
.sync_fmap
(
maps
,
fs
)
?
;
Ok
(
0
)
}
...
...
src/mount/redox/scheme.rs
View file @
e9a7181e
use
std
::
cell
::
RefCell
;
use
std
::
collections
::
BTreeMap
;
use
std
::
result
::
Result
as
StdResult
;
use
std
::
str
;
use
std
::
sync
::
atomic
::{
AtomicUsize
,
Ordering
};
use
std
::
time
::{
SystemTime
,
UNIX_EPOCH
};
...
...
@@ -17,11 +18,81 @@ use node::Node;
use
super
::
resource
::{
Resource
,
DirResource
,
FileResource
};
use
super
::
spin
::
Mutex
;
/// The size to round offset/len up to.
/// This ensures more fmaps can share the same memory even with different parameters.
const
PAGE_SIZE
:
usize
=
4096
;
/// The max amount of fmaps that can be held simultaneously.
/// This restriction is here because we can under no circumstances reallocate,
/// that would invalidate previous mappings.
const
FMAP_AMOUNT
:
usize
=
1024
;
#[derive(Clone,
Copy,
Debug,
Eq,
PartialEq)]
pub
struct
FmapKey
{
pub
block
:
u64
,
pub
offset
:
usize
,
pub
size
:
usize
}
impl
FmapKey
{
pub
fn
round
(
&
self
)
->
FmapKey
{
let
remainder
=
self
.size
%
PAGE_SIZE
;
FmapKey
{
block
:
self
.block
,
offset
:
self
.offset
-
self
.offset
%
PAGE_SIZE
,
size
:
if
remainder
==
0
{
self
.size
}
else
{
self
.size
-
remainder
+
PAGE_SIZE
}
}
}
pub
fn
is_compatible
(
&
self
,
other
:
&
FmapKey
)
->
bool
{
self
.block
==
other
.block
&&
self
.offset
<=
other
.offset
&&
self
.offset
+
self
.size
>=
other
.offset
+
other
.size
}
}
#[derive(Clone)]
pub
struct
FmapValue
{
pub
buffer
:
Vec
<
u8
>
,
/// The actual file length. Syncing only writes &buffer[..actual_size].
pub
actual_size
:
usize
,
pub
refcount
:
usize
}
// NOTE: This can NOT reallocate. That would invalidate previous mappings.
pub
struct
Fmaps
(
Vec
<
Option
<
(
FmapKey
,
FmapValue
)
>>
);
impl
Default
for
Fmaps
{
fn
default
()
->
Fmaps
{
Fmaps
(
vec!
[
None
;
FMAP_AMOUNT
])
}
}
impl
Fmaps
{
pub
fn
find_compatible
(
&
mut
self
,
key
:
&
FmapKey
)
->
StdResult
<
(
usize
,
&
mut
(
FmapKey
,
FmapValue
)),
Option
<
usize
>>
{
let
mut
first_empty
=
None
;
for
(
i
,
entry
)
in
self
.0
.iter_mut
()
.enumerate
()
{
match
entry
{
None
if
first_empty
.is_none
()
=>
first_empty
=
Some
(
i
),
Some
(
entry
)
if
entry
.0
.is_compatible
(
key
)
=>
return
Ok
((
i
,
entry
)),
_
=>
()
}
}
Err
(
first_empty
)
}
pub
fn
index
(
&
mut
self
,
index
:
usize
)
->
&
mut
Option
<
(
FmapKey
,
FmapValue
)
>
{
&
mut
self
.0
[
index
]
}
pub
fn
insert
(
&
mut
self
,
index
:
usize
,
key
:
FmapKey
,
value
:
FmapValue
)
->
&
mut
FmapValue
{
let
elem
=
&
mut
self
.0
[
index
];
assert
!
(
elem
.is_none
());
*
elem
=
Some
((
key
,
value
));
&
mut
elem
.as_mut
()
.unwrap
()
.1
}
}
pub
struct
FileScheme
<
D
:
Disk
>
{
name
:
String
,
fs
:
RefCell
<
FileSystem
<
D
>>
,
next_id
:
AtomicUsize
,
files
:
Mutex
<
BTreeMap
<
usize
,
Box
<
Resource
<
D
>>>>
files
:
Mutex
<
BTreeMap
<
usize
,
Box
<
Resource
<
D
>>>>
,
fmaps
:
Mutex
<
Fmaps
>
}
impl
<
D
:
Disk
>
FileScheme
<
D
>
{
...
...
@@ -30,7 +101,8 @@ impl<D: Disk> FileScheme<D> {
name
:
name
,
fs
:
RefCell
::
new
(
fs
),
next_id
:
AtomicUsize
::
new
(
1
),
files
:
Mutex
::
new
(
BTreeMap
::
new
())
files
:
Mutex
::
new
(
BTreeMap
::
new
()),
fmaps
:
Mutex
::
new
(
Fmaps
::
default
())
}
}
...
...
@@ -651,7 +723,7 @@ impl<D: Disk> Scheme for FileScheme<D> {
// println!("Fsync {}", id);
let
mut
files
=
self
.files
.lock
();
if
let
Some
(
file
)
=
files
.get_mut
(
&
id
)
{
file
.sync
()
file
.sync
(
&
mut
self
.fmaps
.lock
(),
&
mut
self
.fs
.borrow_mut
()
)
}
else
{
Err
(
Error
::
new
(
EBADF
))
}
...
...
@@ -677,10 +749,21 @@ impl<D: Disk> Scheme for FileScheme<D> {
}
}
fn
fmap
(
&
self
,
id
:
usize
,
offset
:
usize
,
size
:
usize
)
->
Result
<
usize
>
{
// println!("Fmap {}, {}, {}", id, offset, size);
let
mut
files
=
self
.files
.lock
();
if
let
Some
(
file
)
=
files
.get_mut
(
&
id
)
{
file
.fmap
(
offset
,
size
,
&
mut
self
.fmaps
.lock
(),
&
mut
self
.fs
.borrow_mut
())
}
else
{
Err
(
Error
::
new
(
EBADF
))
}
}
fn
close
(
&
self
,
id
:
usize
)
->
Result
<
usize
>
{
// println!("Close {}", id);
let
mut
files
=
self
.files
.lock
();
if
files
.remove
(
&
id
)
.is_some
()
{
if
let
Some
(
mut
file
)
=
files
.remove
(
&
id
)
{
let
_
=
file
.funmap
(
&
mut
self
.fmaps
.lock
(),
&
mut
self
.fs
.borrow_mut
());
Ok
(
0
)
}
else
{
Err
(
Error
::
new
(
EBADF
))
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment