Skip to content
This repository has been archived by the owner on Jan 13, 2025. It is now read-only.

Commit

Permalink
bpf_loader: add account_data_region_memory_state helper
Browse files Browse the repository at this point in the history
Shared between serialization and CPI to figure out the MemoryState of an
account.
  • Loading branch information
alessandrod committed Aug 23, 2023
1 parent cb45bdd commit 18ba47c
Show file tree
Hide file tree
Showing 2 changed files with 23 additions and 43 deletions.
38 changes: 19 additions & 19 deletions programs/bpf_loader/src/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use {
solana_rbpf::{
aligned_memory::{AlignedMemory, Pod},
ebpf::{HOST_ALIGN, MM_INPUT_START},
memory_region::MemoryRegion,
memory_region::{MemoryRegion, MemoryState},
},
solana_sdk::{
bpf_loader_deprecated,
Expand Down Expand Up @@ -133,26 +133,14 @@ impl Serializer {
account: &mut BorrowedAccount<'_>,
) -> Result<(), InstructionError> {
if !account.get_data().is_empty() {
let region = if account.can_data_be_changed().is_ok() {
if account.is_shared() {
// If the account is still shared it means it wasn't written to yet during this
// transaction. We map it as CoW and it'll be copied the first time something
// tries to write into it.
let index_in_transaction = account.get_index_in_transaction();

MemoryRegion::new_cow(
account.get_data(),
self.vaddr,
index_in_transaction as u64,
)
} else {
// The account isn't shared anymore, meaning it was written to earlier during
// this transaction. We can just map as writable no need for any fancy CoW
// business.
let region = match account_data_region_memory_state(account) {
MemoryState::Readable => MemoryRegion::new_readonly(account.get_data(), self.vaddr),
MemoryState::Writable => {
MemoryRegion::new_writable(account.get_data_mut()?, self.vaddr)
}
} else {
MemoryRegion::new_readonly(account.get_data(), self.vaddr)
MemoryState::Cow(index_in_transaction) => {
MemoryRegion::new_cow(account.get_data(), self.vaddr, index_in_transaction)
}
};
self.vaddr += region.len;
self.regions.push(region);
Expand Down Expand Up @@ -615,6 +603,18 @@ pub fn deserialize_parameters_aligned<I: IntoIterator<Item = usize>>(
Ok(())
}

pub(crate) fn account_data_region_memory_state(account: &BorrowedAccount<'_>) -> MemoryState {
if account.can_data_be_changed().is_ok() {
if account.is_shared() {
MemoryState::Cow(account.get_index_in_transaction() as u64)
} else {
MemoryState::Writable
}
} else {
MemoryState::Readable
}
}

#[cfg(test)]
#[allow(clippy::indexing_slicing)]
mod tests {
Expand Down
28 changes: 4 additions & 24 deletions programs/bpf_loader/src/syscalls/cpi.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
super::*,
crate::declare_syscall,
crate::{declare_syscall, serialization::account_data_region_memory_state},
log::debug,
scopeguard::defer,
solana_program_runtime::invoke_context::SerializedAccountMetadata,
Expand Down Expand Up @@ -1282,29 +1282,9 @@ fn update_caller_account_perms(

let data_region = account_data_region(memory_mapping, *vm_data_addr, *original_data_len)?;
if let Some(region) = data_region {
match (
region.state.get(),
callee_account.can_data_be_changed().is_ok(),
) {
(MemoryState::Readable, true) => {
// If the account is still shared it means it wasn't written to yet during this
// transaction. We map it as CoW and it'll be copied the first time something
// tries to write into it.
if callee_account.is_shared() {
let index_in_transaction = callee_account.get_index_in_transaction();
region
.state
.set(MemoryState::Cow(index_in_transaction as u64));
} else {
region.state.set(MemoryState::Writable);
}
}

(MemoryState::Writable | MemoryState::Cow(_), false) => {
region.state.set(MemoryState::Readable);
}
_ => {}
}
region
.state
.set(account_data_region_memory_state(callee_account));
}
let realloc_region = account_realloc_region(
memory_mapping,
Expand Down

0 comments on commit 18ba47c

Please sign in to comment.