use crate::fs::Lfs;
use crate::types::lfs_block_t;
pub unsafe fn lfs_alloc_ckpoint(lfs: *mut Lfs) {
let lfs = &mut *lfs;
lfs.lookahead.ckpoint = lfs.block_count;
}
pub fn lfs_alloc_drop(lfs: *mut Lfs) {
unsafe {
(*lfs).lookahead.size = 0;
(*lfs).lookahead.next = 0;
unsafe { lfs_alloc_ckpoint(lfs) };
}
}
unsafe extern "C" fn lfs_alloc_lookahead_cb(
data: *mut core::ffi::c_void,
block: lfs_block_t,
) -> i32 {
lfs_alloc_lookahead(data as *mut Lfs, block)
}
pub fn lfs_alloc_lookahead(p: *mut Lfs, block: lfs_block_t) -> i32 {
unsafe {
let lfs = &mut *p;
let off = (block.wrapping_sub(lfs.lookahead.start)).wrapping_add(lfs.block_count)
% lfs.block_count;
if off < lfs.lookahead.size {
let buf = lfs.lookahead.buffer;
if !buf.is_null() {
let byte_idx = (off / 8) as usize;
let bit = 1u8 << (off % 8);
*buf.add(byte_idx) |= bit;
}
}
0
}
}
pub fn lfs_alloc_scan(lfs: *mut Lfs) -> i32 {
use crate::fs::traverse::lfs_fs_traverse_;
use crate::util::lfs_min;
crate::lfs_trace!("alloc_scan: start");
unsafe {
let lfs_ref = &mut *lfs;
let cfg = lfs_ref.cfg.as_ref().expect("cfg");
let buf = lfs_ref.lookahead.buffer;
if buf.is_null() {
return crate::error::LFS_ERR_NOSPC;
}
lfs_ref.lookahead.start =
(lfs_ref.lookahead.start + lfs_ref.lookahead.next) % lfs_ref.block_count;
lfs_ref.lookahead.next = 0;
lfs_ref.lookahead.size = lfs_min(8 * cfg.lookahead_size, lfs_ref.lookahead.ckpoint);
core::ptr::write_bytes(buf, 0, cfg.lookahead_size as usize);
let err = lfs_fs_traverse_(
lfs,
Some(lfs_alloc_lookahead_cb),
lfs as *mut core::ffi::c_void,
true,
);
if err != 0 {
crate::lfs_trace!("alloc_scan: traverse err={}", err);
lfs_alloc_drop(lfs);
return crate::lfs_pass_err!(err);
}
crate::lfs_trace!("alloc_scan: done");
0
}
}
pub fn lfs_alloc(lfs: *mut Lfs, block: *mut lfs_block_t) -> i32 {
use crate::error::LFS_ERR_NOSPC;
unsafe {
let lfs = &mut *lfs;
let buf = lfs.lookahead.buffer;
if buf.is_null() {
return crate::lfs_err!(LFS_ERR_NOSPC);
}
#[cfg(feature = "loop_limits")]
const MAX_ALLOC_ITER: u32 = 1024;
#[cfg(feature = "loop_limits")]
let mut alloc_iter: u32 = 0;
loop {
#[cfg(feature = "loop_limits")]
{
if alloc_iter >= MAX_ALLOC_ITER {
panic!(
"loop_limits: MAX_ALLOC_ITER ({}) exceeded in lfs_alloc",
MAX_ALLOC_ITER
);
}
alloc_iter += 1;
}
while lfs.lookahead.next < lfs.lookahead.size {
if (*buf.add((lfs.lookahead.next / 8) as usize)) & (1u8 << (lfs.lookahead.next % 8))
== 0
{
*block = (lfs.lookahead.start + lfs.lookahead.next) % lfs.block_count;
#[cfg(feature = "loop_limits")]
const MAX_ALLOC_SCAN_BIT_ITER: u32 = 4096;
#[cfg(feature = "loop_limits")]
let mut bit_iter: u32 = 0;
loop {
#[cfg(feature = "loop_limits")]
{
if bit_iter >= MAX_ALLOC_SCAN_BIT_ITER {
panic!(
"loop_limits: MAX_ALLOC_SCAN_BIT_ITER ({}) exceeded",
MAX_ALLOC_SCAN_BIT_ITER
);
}
bit_iter += 1;
}
lfs.lookahead.next += 1;
lfs.lookahead.ckpoint = lfs.lookahead.ckpoint.wrapping_sub(1);
if lfs.lookahead.next >= lfs.lookahead.size {
return 0;
}
let next_byte = (lfs.lookahead.next / 8) as usize;
let next_bit = 1u8 << (lfs.lookahead.next % 8);
if (*buf.add(next_byte)) & next_bit == 0 {
return 0;
}
}
}
lfs.lookahead.next += 1;
lfs.lookahead.ckpoint = lfs.lookahead.ckpoint.wrapping_sub(1);
}
if lfs.lookahead.ckpoint == 0 {
crate::lfs_trace!(
"No more free space 0x{:08x} (ckpoint==0)",
(lfs.lookahead.start + lfs.lookahead.next) % lfs.block_count
);
return crate::lfs_err!(LFS_ERR_NOSPC);
}
let err = lfs_alloc_scan(lfs);
if err != 0 {
crate::lfs_trace!(
"lfs_alloc NOSPC: alloc_scan returned {} start={} next={}",
err,
lfs.lookahead.start,
lfs.lookahead.next
);
return crate::lfs_pass_err!(err);
}
}
}
}