File System Architecture
Document History
| Date | Author | Comments |
|---|---|---|
| 2024-12-12 | G.Weatherup | Initial comprehensive specification |
Draft Document
This document is currently in draft form and under active discussion. Specifications, examples, and recommendations may change based on review feedback and implementation experience.
Related Pages
Related Pages
Purpose
This document defines the system-wide file system architecture for RDK platforms, establishing a layered, modular approach that supports independent versioning, freezeable layers, and binary compatibility across multiple mount points.
The specification enables:
- Independent Layer Updates: Each layer (/vendor, /mw, /product, /apps) can be versioned, frozen, and updated independently
- Module Traceability: Clear visibility into what modules are built, delivered, and deployed
- Bootloader Flexibility: Kernel-driven mounting with bootloader configuration for binary compatibility
- Development Clarity: Well-defined locations for deliverables from each development team
Architectural Overview
Layered File System Model
The RDK platform adopts a multi-layer architecture where each layer represents a distinct functional and organizational boundary:
block-beta
columns 1
block:apps
apps_label["/apps (optional)<br/>Application layer"]
end
space
block:product
product_label["/product<br/>Product-specific customizations"]
end
space
block:mw
mw_label["/mw<br/>Middleware layer"]
end
space
block:vendor
vendor_label["/vendor<br/>Vendor/SoC layer"]
end
space
block:rootfs
rootfs_label["/ (rootfs)<br/>Minimal root filesystem"]
end
space
block:kernel
kernel_label["Kernel + Bootloader<br/>Hardware initialization"]
end
apps --> product
product --> mw
mw --> vendor
vendor --> rootfs
rootfs --> kernel
style apps fill:#e1f5ff,stroke:#01579b,stroke-width:2px
style product fill:#fff4e1,stroke:#e65100,stroke-width:2px
style mw fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
style vendor fill:#fce4ec,stroke:#c2185b,stroke-width:2px
style rootfs fill:#f3e5f5,stroke:#6a1b9a,stroke-width:2px
style kernel fill:#e0e0e0,stroke:#424242,stroke-width:2px
Layer Characteristics
Each layer in the system has the following characteristics:
| Layer | Purpose | Freeze Cadence | Independence | OSS Components |
|---|---|---|---|---|
| Kernel | Hardware initialization, bootloader integration | Low (rarely changes) | Fully independent | Kernel-specific only |
| rootfs (/) | Minimal system-wide essentials | Low (stable base) | System foundation | Core utilities only |
| /vendor | SoC/hardware abstraction layer | Low-Medium (will freeze) | Independent mount | Vendor-specific OSS |
| /mw | RDK middleware services | Medium (may freeze later) | Independent mount | Middleware OSS |
| /product | Product customisations | Low-Medium (will freeze) | Independent mount | Configuration only; OSS delivered by /apps, /mw, or /vendor |
| /apps | Application layer | High | Independent mount | Application OSS |
Key Design Principles
- Freezeable Layers: Any layer can be frozen with a stable version, reducing update frequency
- Independent Binaries: Each layer is a separate mountable image with its own versioning
- No Cross-Layer Pollution: Libraries and components remain within their designated layer
- Bootloader-Driven Configuration: Mount points determined at boot time via bootloader
- Traceability: All modules are auditable through configuration files and version metadata
Kernel and Boot Sequence
Kernel Role
The kernel is an independent bootable binary responsible for:
- Hardware initialization and driver loading
- Mounting the root filesystem (rootfs)
- Reading mount configuration provided by the bootloader
- Executing the mount sequence for additional layers
Bootloader Configuration
During the boot sequence, the bootloader provides the kernel with configuration specifying:
- Which layers to mount (/vendor, /mw, /product, /apps)
- Version identifiers for each layer
- Mount options and priorities
- Fallback configurations for resilience
This enables binary compatibility flexibility — the same kernel can work with different combinations of layer versions based on bootloader settings.
Example bootloader configuration:
vendor_version=2.5.0
vendor_image=/boot/vendor-2.5.0.img
mw_version=3.1.0
mw_image=/boot/mw-3.1.0.img
product_version=1.0.5
product_image=/boot/product-1.0.5.img
apps_enabled=true
apps_image=/boot/apps-1.2.0.img
Mount Sequence
The kernel executes the following mount sequence:
- Mount rootfs (/) from kernel-supplied initramfs or separate partition
- Read bootloader configuration from kernel command line or device tree
- Mount /vendor layer (required)
- Mount /mw layer (required)
- Mount /product layer (required)
- Mount /apps layer (if specified)
- Execute systemd initialization with full layer visibility
Boot Sequence and Systemd Targets
The following diagram illustrates the complete boot sequence including systemd layer milestone targets:
graph TD
Start[Kernel Boot] --> MountLayers[Mount Layers: /vendor, /mw, /product, /apps]
MountLayers --> Ldconfig[ldconfig: Regenerate dynamic linker cache]
Ldconfig --> SystemdInit[Systemd Init]
SystemdInit --> VendorEarly[vendor-early.target]
VendorEarly --> VendorServices[Vendor Services Start]
VendorServices --> VendorLate[vendor-late.target]
VendorLate --> MwEarly[mw-early.target]
MwEarly --> MwServices[MW Services Start]
MwServices --> GraphicsReady[Graphics Ready Milestone?]
GraphicsReady --> MwLate[mw-late.target]
MwLate --> AppEarly[app-early.target]
AppEarly --> AppServices[Application Services Start]
AppServices --> AppLate[app-late.target]
AppLate --> MultiUser[multi-user.target]
style VendorEarly fill:#fce4ec,stroke:#c2185b
style VendorLate fill:#fce4ec,stroke:#c2185b
style MwEarly fill:#e8f5e9,stroke:#2e7d32
style MwLate fill:#e8f5e9,stroke:#2e7d32
style AppEarly fill:#e1f5ff,stroke:#01579b
style AppLate fill:#e1f5ff,stroke:#01579b
Milestone Targets:
- vendor-early.target: Critical vendor services needed before middleware starts (e.g., essential hardware drivers)
- vendor-late.target: Full vendor layer operational (all vendor services running)
- mw-early.target: Middleware early initialization services
- Graphics Ready: Optional milestone indicating graphics subsystem is ready for applications
- mw-late.target: Full middleware stack operational (all RDK services running)
- app-early.target: Application layer initialization
- app-late.target: All applications running
- multi-user.target: System fully operational
Boot Control: Middleware controls the overall boot sequence but delegates to layer-specific milestone targets. Each layer's internal service ordering and dependencies are the responsibility of that layer, maintaining independence.
Root Filesystem (/)
Stripped-Down Design
The rootfs is intentionally minimal, containing only:
- Essential system utilities (init, systemd, basic shell)
- Core libraries required for system bootstrap
- Kernel modules and firmware
- Mount point directories for additional layers
- Symbolic links for common directories
Common Directory Structure
Standard directories are reorganized to support the layered architecture:
| Traditional Path | New Architecture | Notes |
|---|---|---|
/usr/lib |
Symlinks to layer-specific lib directories | See Dynamic Linking section |
/etc |
Layer-specific configs under /vendor/*/etc, /mw/*/etc |
Managed via symlinks |
/var/log |
Symlinks to /var/log/{vendor,mw,product,apps}/* |
Per-layer logging |
/opt |
Deprecated in favor of layer-specific paths | Legacy support only |
/usr/bin |
Layer-specific bin directories | Invoked via absolute paths |
Symbolic Link Strategy
The rootfs creates symbolic links at boot time to integrate layer-specific directories:
# Dynamic library paths
/usr/lib/vendor -> /vendor/lib
/usr/lib/mw -> /mw/lib
# Configuration merging
/etc/vendor -> /vendor/etc
/etc/mw -> /mw/etc
# Logging directories (writable, separate from read-only layers)
# Individual module logs are at /var/log/<layer>/<module>/
# Created by layer init process during boot
Layer-Specific Architecture
/vendor Layer
The vendor layer provides hardware abstraction and SoC-specific functionality.
Directory Structure:
/vendor/
├── <module>/
│ ├── bin/ # Module executables
│ ├── lib/ # Shared libraries
│ ├── etc/ # Configuration files
│ ├── systemd/ # Service definitions
│ ├── app_armor/ # Security profiles
│ ├── ld.so.conf.d/ # Linker configuration
│ ├── memory/ # Resource declarations
│ ├── logs/ -> /var/log/vendor/<module>/
│ └── VERSION # Version metadata
├── lib/ # Aggregated libraries
├── bin/ # Aggregated executables
└── etc/ # Aggregated configurations
Independent OSS Components: The vendor layer maintains its own Open Source Software components (e.g., vendor-specific drivers, libraries) and consumes them exclusively from /vendor mount points.
/mw Layer
The middleware layer provides RDK core services and framework components.
Directory Structure:
/mw/
├── <module>/
│ ├── bin/ # Middleware executables
│ ├── lib/ # RDK middleware libraries
│ ├── etc/ # Service configurations
│ ├── systemd/ # Service definitions
│ ├── app_armor/ # Security profiles
│ ├── ld.so.conf.d/ # Linker configuration
│ ├── memory/ # Resource declarations
│ ├── logs/ -> /var/log/mw/<module>/
│ └── VERSION # Version metadata
├── lib/ # Aggregated libraries
├── bin/ # Aggregated executables
└── etc/ # Aggregated configurations
Independent OSS Components: Middleware OSS components (e.g., GStreamer, D-Bus wrappers, RDK service libraries) are consumed from /mw mount points only.
/product Layer
The product layer provides product-specific configurations and customizations. This layer contains configuration only, not platform-specific binaries or libraries.
Delivery Mechanism
The /product layer is delivered by the image assembler during image composition. Unlike /vendor (which is SoC-specific) and /mw (which is platform-independent), the /product layer captures platform-level configurations that may be shared across multiple SoCs within the same product family. This allows the same kernel and vendor layers to support multiple product configurations through different /product images. The /apps layer is also platform-independent.
Directory Structure:
/product/
├── etc/
│ └── <component>/ # Component-specific configurations
│ └── *.yaml # Configuration files (YAML for human readability)
├── data/ # Product assets (images, branding)
├── logs/ -> /var/log/product/
└── VERSION # Version metadata
Configuration Only: The product layer is restricted to configuration files, assets, and data. Platform-specific executables and libraries must reside in the /vendor or /mw layers.
All product-specific configuration files should be organized under /product/etc/ in component-specific subdirectories for clear organization and maintainability. Configuration files use YAML format to provide human-readable content with support for comments.
Example:
/product/etc/as/config.yaml # Application Services configuration
/product/etc/entservices/config.yaml # Enterprise services configuration
/product/etc/rdkappmanager/config.yaml # RDK App Manager configuration
/apps Layer (Optional)
The application layer provides end-user applications and services.
Directory Structure:
/apps/
├── <app>/
│ ├── bin/ # Application binaries
│ ├── lib/ # Application-specific libraries
│ ├── etc/ # Application configurations
│ ├── data/ # Application data
│ ├── logs/ -> /var/log/apps/<app>/
│ └── VERSION # Version metadata
└── ...
Independent OSS Components: Application OSS dependencies are isolated to /apps mount points.
Dynamic Linking and Library Management
Layer-Specific Library Paths
Each layer maintains its own dynamic linker configuration:
# Vendor layer
/vendor/lib/
/vendor/<module>/lib/
# Middleware layer
/mw/lib/
/mw/<module>/lib/
# Product layer (configuration only - no lib directories)
# Apps layer
/apps/lib/
/apps/<app>/lib/
Linker Configuration
Each module provides linker configuration in /etc/ld.so.conf.d/:
# Vendor module example
/etc/ld.so.conf.d/vendor-<module>.conf -> /vendor/<module>/ld.so.conf.d/vendor-<module>.conf
# Middleware module example
/etc/ld.so.conf.d/mw-<module>.conf -> /mw/<module>/ld.so.conf.d/mw-<module>.conf
Runtime Linking Policy
- RPATH Priority: Modules should embed RPATH during compilation (
-Wl,-rpath,/<layer>/<module>/lib) - No LD_LIBRARY_PATH: Environment variables must not be relied upon
- Layer Isolation: Libraries from one layer should not directly depend on another layer's internal libraries
- Shared Dependencies: Common dependencies (e.g., glibc) provided by rootfs
For detailed linking specifications, see Directory And Dynamic Linking Specification.
Module Traceability and Auditing
Configuration Files
Each module must include configuration files that enable traceability:
/<layer>/<module>/
├── VERSION # Version and build metadata
├── etc/manifest.json # Module dependencies and capabilities
└── memory/usage.conf # Resource declarations
VERSION File Format
version=MAJOR.MINOR.PATCH
build_date=YYYY-MM-DD HH:MM:SS UTC
build_sha=sha256:<commit-hash>
layer=vendor|mw|product|apps
dependencies=<comma-separated list>
Manifest File Format
The manifest file is typically generated automatically by the build system (e.g., Yocto/BitBake) from recipe metadata during compilation. The specific generation mechanism depends on your vendor layer build setup.
Example Yocto Generation Approach:
In a Yocto recipe or custom bbclass, manifest generation can leverage recipe variables:
# Example in a custom manifest.bbclass or recipe do_install_append
do_install_append() {
install -d ${D}${sysconfdir}
cat > ${D}${sysconfdir}/manifest.json << EOF
{
"module": "${PN}",
"version": "${PV}",
"layer": "${LAYER_TYPE}",
"dependencies": {
"runtime": [$(echo "${RDEPENDS_${PN}}" | sed 's/ /", "/g' | sed 's/^/"/;s/$/"/')],
"build": [$(echo "${DEPENDS}" | sed 's/ /", "/g' | sed 's/^/"/;s/$/"/')]
},
"provides": ["${RPROVIDES}"],
"conflicts": [],
"oss_components": [
{"name": "${PN}", "version": "${PV}", "license": "${LICENSE}"}
]
}
EOF
}
JSON Format:
{
"module": "module-name",
"version": "1.2.3",
"layer": "vendor",
"dependencies": {
"runtime": ["module-a:1.0.0", "module-b:2.1.0"],
"build": ["toolchain:11.0"]
},
"provides": ["libmodule.so.1", "module-daemon"],
"conflicts": [],
"oss_components": [
{"name": "library-x", "version": "3.4.5", "license": "Apache-2.0"}
]
}
Build System Integration
The manifest generation approach shown above is an example. Your vendor layer build infrastructure may implement this differently using custom bbclasses, buildhistory integration, or image postprocessing commands. Consult your vendor layer documentation for specific implementation details.
Runtime Auditing
Scripts can audit the system by scanning layer directories:
# Audit all vendor modules
for module in /vendor/*/VERSION; do
echo "Module: $(dirname $module)"
cat $module
done
# Check OSS component usage
find /vendor /mw /product /apps -name manifest.json -exec jq '.oss_components' {} \;
# Verify memory declarations
find /vendor /mw -name usage.conf -exec cat {} \;
This enables:
- Build Verification: Confirm what was built and its version
- Deployment Validation: Verify what is actually deployed
- Audit Reports: Generate reports on module versions and OSS usage
Integration Requirements
Module Development Guidelines
Development teams must follow these guidelines for each layer:
- Directory Structure: Follow the prescribed layout for the target layer
- VERSION Files: Include comprehensive version metadata
- Manifest Files: Declare all dependencies and provided components
- Linker Configuration: Provide ld.so.conf.d entries for dynamic libraries
- Logging Integration: Use layer-specific log paths (see Logging System)
- Security Profiles: Include AppArmor profiles where applicable
- Service Definitions: Provide systemd units with correct layer dependencies
Cross-Layer Dependencies
While layers are independent, controlled dependencies are permitted:
- Upward Dependencies: Upper layers may depend on lower layers (e.g., /mw depends on /vendor)
- No Downward Dependencies: Lower layers must not depend on upper layers
- Interface Contracts: Dependencies must be through well-defined interfaces (e.g., AIDL/Binder)
- Version Pinning: Dependencies must specify version requirements in manifest files
Build and Deployment
Build Time:
- Each layer is built independently
- Dependencies resolved against frozen layer versions
- Output is a mountable image per layer
Deployment:
- Bootloader configuration updated with new layer versions
- Kernel mounts layers during boot sequence
- Systemd initializes services across all mounted layers
Update Strategy:
- Individual layers can be updated without rebuilding others
- Bootloader configuration points to new layer version
- Rollback supported by reverting bootloader configuration
Future Considerations
Freezeable Layers
As the platform matures, layers will progressively freeze:
- Phase 1: Vendor layer stabilizes and reduces update cadence
- Phase 2: Middleware layer freezes after API stabilization
- Phase 3: Product and Apps layers continue high-frequency updates
Frozen layers provide:
- Binary Stability: No ABI/API changes within major version
- Reduced Testing: Frozen layers need less regression testing
- Faster Updates: Upper layers update without rebuilding lower layers
Alternative Configurations
The architecture supports flexibility for different deployment scenarios:
- Monolithic Mode: All layers merged into single rootfs (development/testing)
- Hybrid Mode: Some layers merged, others separate (transitional)
- Fully Layered: All layers independent (production target)
Bootloader configuration determines which mode is active.
Compliance and Governance
Layer Responsibilities
| Layer | Responsible Team | Governance |
|---|---|---|
| Kernel | Platform/SoC vendor | Upstream kernel + vendor patches |
| rootfs | Platform team | RDK community + platform leads |
| /vendor | SoC vendor | Vendor-specific |
| /mw | RDK middleware team | RDK community governance |
| /product | Product teams | Product-specific |
| /apps | Application teams | Application-specific |
Review and Approval
Changes to this specification require:
- Review by RDK architecture team
- Approval from affected layer owners
- Impact assessment on existing deployments
- Migration plan for breaking changes
Summary
This file system architecture provides:
- Clear Separation: Each layer has well-defined boundaries and responsibilities
- Independent Evolution: Layers can be versioned and frozen independently
- Traceability: Modules and OSS components are auditable
- Flexibility: Bootloader-driven configuration supports multiple deployment modes
- Maintainability: Reduced complexity through layer isolation
For implementation details on individual modules, see Directory And Dynamic Linking Specification.