-
Notifications
You must be signed in to change notification settings - Fork 0
Block Device Layer
The block I/O layer provides byte-level read/write/flush operations on storage devices, with support for partition mapping, sector alignment, and filesystem probing.
The block device layer sits between physical storage drivers (IDE, SCSI, USB, RAMdisk) and higher-level consumers (filesystems, the VFS layer). It defines a hierarchy of APIs that add increasingly specific capabilities:
- BlockDeviceAPI — base contract for raw block I/O
- PartitionableBlockDeviceAPI — adds partition table access and sector size queries
- FSBlockDeviceAPI — for devices that may contain a filesystem
Wrapper classes inject cross-cutting concerns (alignment, offset-mapping) without altering the underlying driver. This design isolates physical device specifics from higher-level code.
| Class / File | Role |
|---|---|
fs/src/driver/org/jnode/driver/block/BlockDeviceAPI.java |
Base interface: read, write, flush, getLength
|
fs/src/driver/org/jnode/driver/block/PartitionableBlockDeviceAPI.java |
Adds getSectorSize, getPartitionTable
|
fs/src/driver/org/jnode/driver/block/FSBlockDeviceAPI.java |
Adds getSectorSize, getPartitionTableEntry
|
fs/src/driver/org/jnode/driver/block/BlockAlignmentSupport.java |
Wraps a BlockDeviceAPI, enforcing sector-aligned reads/writes |
fs/src/driver/org/jnode/driver/block/FSBlockAlignmentSupport.java |
Wraps an FSBlockDeviceAPI, adding alignment |
fs/src/driver/org/jnode/driver/block/PartitionableBlockAlignmentSupport.java |
Wraps a PartitionableBlockDeviceAPI, adding alignment |
fs/src/driver/org/jnode/driver/block/MappedBlockDeviceSupport.java |
Virtual sub-device: maps an offset/length region of a parent device |
fs/src/driver/org/jnode/driver/block/MappedFSBlockDeviceSupport.java |
FSBlockDeviceAPI-aware version of mapped support |
fs/src/driver/org/jnode/driver/block/BlockDeviceAPIHelper.java |
Static helpers: checkBounds, checkAlignment
|
fs/src/driver/org/jnode/driver/block/FileDevice.java |
FSBlockDeviceAPI backed by a host file (for testing) |
fs/src/driver/org/jnode/driver/block/ByteArrayDevice.java |
BlockDeviceAPI backed by an in-memory byte array |
fs/src/driver/org/jnode/driver/block/JarFileDevice.java |
Read-only FSBlockDeviceAPI backed by a JAR |
fs/src/driver/org/jnode/driver/block/Geometry.java |
CHS geometry descriptor (cylinders/heads/sectors) |
fs/src/driver/org/jnode/driver/block/CHS.java |
Cylinder-head-sector value holder |
fs/src/driver/org/jnode/driver/block/ide/, scsi/, floppy/, usb/, ramdisk/
|
Physical device driver implementations |
The three interfaces form a linear hierarchy:
DeviceAPI
└── BlockDeviceAPI
├── PartitionableBlockDeviceAPI<PTE>
└── FSBlockDeviceAPI
BlockDeviceAPI is the contract every block device must implement:
public interface BlockDeviceAPI extends DeviceAPI {
long getLength() throws IOException;
void read(long devOffset, ByteBuffer dest) throws IOException;
void write(long devOffset, ByteBuffer src) throws IOException;
void flush() throws IOException;
}PartitionableBlockDeviceAPI extends this for devices with MBR/GPT partition tables:
public interface PartitionableBlockDeviceAPI<PTE extends PartitionTableEntry>
extends BlockDeviceAPI {
int getSectorSize() throws IOException;
PartitionTable<PTE> getPartitionTable() throws IOException;
}FSBlockDeviceAPI extends BlockDeviceAPI for devices that may hold a filesystem. Unlike PartitionableBlockDeviceAPI, it is used by virtual partition devices (created via MappedFSBlockDeviceSupport):
public interface FSBlockDeviceAPI extends BlockDeviceAPI {
int getSectorSize() throws IOException;
PartitionTableEntry getPartitionTableEntry();
}Physical devices (IDE disk, SCSI disk) implement PartitionableBlockDeviceAPI. The getPartitionTable() method reads the MBR/GPT from the device and returns a parsed PartitionTable. Each PartitionTableEntry contains the start LBA, length, and type of a partition.
From each entry, JNode creates a virtual child device using MappedFSBlockDeviceSupport:
// Inside PartitionManager or DeviceManager:
for (PartitionTableEntry entry : partitionTable.getEntries()) {
MappedFSBlockDeviceSupport partDevice =
new MappedFSBlockDeviceSupport(parentDevice, entry.getStartLBA() * sectorSize,
entry.getLength());
}This virtual device presents an FSBlockDeviceAPI to upper layers. The offset is pre-adjusted so callers see the partition's logical address space starting at zero. Reads/writes are transparently redirected to the parent device at offset + devOffset.
Physical devices often require I/O requests aligned to the sector size (typically 512 or 4096 bytes). The BlockAlignmentSupport wrapper handles this by decomposing unaligned requests into a combination of HEAD, BODY, and TAIL operations:
- HEAD — partial block before the first aligned boundary
- BODY — fully aligned blocks in the middle
- TAIL — partial block after the last aligned boundary
The read and write paths detect four buffer states:
- EMPTY — zero-length request, no I/O
- ALIGNED — offset and length are multiples of alignment, direct pass-through
- CONTAINED — request fits within a single aligned block, read-modify-write
- CROSSED — spans multiple aligned blocks, HEAD + BODY + TAIL
This minimizes buffer copies: at most 2 auxiliary reads/writes (HEAD + TAIL) are needed; the BODY passes directly to the underlying device.
The relationship is layered:
Physical Driver (IDE, SCSI)
└── implements PartitionableBlockDeviceAPI
└── BlockAlignmentSupport (wraps, adds alignment)
└── MappedFSBlockDeviceSupport (creates partition view)
└── registers FSBlockDeviceAPI
└── FileSystemType.probe(device)
└── creates FileSystem
The filesystem driver (e.g., FAT, ext2, ISO9660) calls FileSystemType.create(device, readOnly), passing a device that exposes FSBlockDeviceAPI. The FileSystemType implementation probes the device by reading its superblock and checking known magic bytes.
Concrete FSBlockDeviceAPI implementations:
-
FileDevice— backed by a host OS file, used in boot image and testing -
JarFileDevice— backed by a JAR entry (read-only) -
MappedFSBlockDeviceSupport— virtual device for partitions
Concrete BlockDeviceAPI implementations:
-
ByteArrayDevice— in-memory block device, used in tests - Physical drivers in
ide/,scsi/,usb/,ramdisk/,floppy/
-
FSBlockDeviceAPIvsPartitionableBlockDeviceAPI: These are parallel hierarchies, not substitutes. Physical partitioned devices implementPartitionableBlockDeviceAPI; their virtual partition children implementFSBlockDeviceAPI. A filesystem driver should expectFSBlockDeviceAPI, notPartitionableBlockDeviceAPI. -
Offset translation: When reading from a
MappedBlockDeviceSupport, the passed offset is relative to the partition start, not the start of the whole device. This is handled by the mapping class itself, delegatingoffset + devOffsetto the parent. -
Alignment is a wrapper, not automatic: Drivers do not automatically enforce sector alignment. Code that needs alignment must explicitly wrap with
BlockAlignmentSupportorFSBlockAlignmentSupport. -
ByteArrayDeviceread is non-seekable: It copies bytes directly from the array usingSystem.arraycopywith a cast tointoffset. Works for small in-memory devices but cannot address byte ranges beyondInteger.MAX_VALUE. -
Partition table parsing:
getPartitionTable()can returnnullif no valid partition table is found (e.g., unformatted disk or newer GPT not yet supported).
- Driver-Framework — device and driver management
- Device-Manager — device tree and API binding
- Filesystem-Layer — VFS, partition tables, and fs driver integration
- IDEDisk-Driver — primary IDE disk driver implementation
- VFS-Layer — filesystem type probing, mount mechanism
- Resource-Management — IRQ/IO/DMA resource allocation for block devices