SquashFS
SquashFS is a compressed, read-only filesystem for Linux that enables efficient storage of files, inodes, and directories by applying compression algorithms such as zlib, LZ4, LZO, XZ, or Zstd.[1] It supports block sizes up to 1 MiB (with a default of 128 KiB) and is designed for scenarios requiring low overhead, such as embedded systems and archival applications.[1] Development of SquashFS began in 2002 under the leadership of Phillip Lougher, initially as a highly compressed filesystem for tiny and embedded Linux systems.[2] The project saw releases like version 3.0 in 2006, which introduced support for larger block sizes.[3] By 2008, a rewritten version was submitted for inclusion in the Linux kernel mainline, and it was merged into kernel version 2.6.29 in early 2009.[4] Subsequent versions added support for additional compression methods and improved performance, with tools maintained on GitHub as of the latest release 4.7.4 in November 2025.[5] Key features of SquashFS include support for sparse files, hard links, directory indexes, and extended attributes (xattrs), though it lacks access control lists (ACLs).[1] It accommodates filesystems up to 2^64 bytes in size, individual files up to approximately 2 TiB, and an unlimited number of files and directories.[1] Metadata is highly optimized, with inodes averaging just 8 bytes, and internal caching mechanisms for metadata and file fragments enhance read performance.[1] SquashFS is widely used in embedded Linux devices for root filesystems where write access is unnecessary, as well as in live distributions and bootable media to reduce image sizes.[6] For example, it serves as an alternative to traditional archives like tarballs by providing mountable, compressed storage with better flexibility and speed.[7] Its read-only nature makes it suitable for firmware images and systems prioritizing space efficiency over modifiability.[8]Overview
Definition and Purpose
SquashFS is a highly compressed, read-only filesystem designed for Linux, enabling the storage of entire file hierarchies within a single file or block device.[1] It compresses not only files but also metadata such as inodes and directories to maximize space efficiency, supporting block sizes from 4 KiB to 1 MiB (default 128 KiB) and various compression algorithms.[1] This structure allows SquashFS images to be mounted directly as filesystems, providing transparent access to the compressed data without extraction.[4] The primary purpose of SquashFS is to facilitate space-efficient storage in environments where write operations are not required, such as archival systems, distribution media like live CDs, and resource-constrained embedded devices.[9] By generating a compact, mountable image of a directory hierarchy, it reduces storage footprints significantly—often achieving compression ratios superior to traditional archives while maintaining filesystem semantics.[10] This makes it ideal for scenarios demanding minimal disk or memory usage, including bootable media and firmware images where immutability enhances reliability.[4] Unlike read-write filesystems such as ext4, which support dynamic modifications and journaling for data integrity, read-only filesystems like SquashFS prioritize compression and immutability over mutability, eliminating the need for write buffers or consistency checks during operation. SquashFS originated in 2002, developed by Phillip Lougher to address the need for a low-overhead, highly compressed alternative to earlier read-only filesystems like CramFS, particularly for reducing the size of Linux distributions and enabling efficient archival and embedded applications.[10]Key Features
SquashFS is a highly compressed, read-only filesystem designed for Linux, offering POSIX compliance to ensure compatibility with standard Unix file operations, including support for regular files, directories, symbolic links, device nodes, and other Unix file types.[1] It also includes extended attributes (xattrs) to store additional metadata, such as security labels for SELinux; POSIX ACLs can be stored but are not enforced by the filesystem.[1] The filesystem accommodates large-scale storage with a maximum size of 16 EiB (2^64 bytes) and individual file sizes up to approximately 2 TiB, while supporting configurable block sizes ranging from 4 KiB to 1 MiB to optimize compression and performance.[11] For compression, SquashFS supports multiple algorithms—gzip (via zlib) for balanced performance, LZMA2 (via xz) for high compression ratios at the cost of slower decompression, LZO for moderate compression with fast processing, LZ4 for rapid compression and decompression with lower ratios, and Zstandard (Zstd) for efficient ratios and speeds suitable for modern hardware—allowing users to trade off space savings against access times.[12] Additional capabilities include duplicate file detection for automatic deduplication during image creation, which reduces redundancy by storing identical files only once, and support for sparse files to efficiently represent files with large gaps of empty space.[12] Filenames are case-sensitive and limited to 255 characters, aligning with common Unix conventions.[11] As a strictly read-only filesystem, SquashFS does not support write operations, journaling for crash recovery, or built-in encryption; instead, modifications require recreating the image with tools like mksquashfs, and security features such as encryption must rely on external mechanisms like device mapper.[1]Technical Details
File System Layout
The SquashFS file system is organized into a sequence of up to nine byte-aligned components: the superblock, compression options, inode table, directory table, fragment table, lookup table, export table, UID/GID table, and extended attribute (xattr) table, followed by data blocks and fragments.[1] This layout enables efficient random access to compressed data by storing metadata before file contents, with all elements except data blocks compressed in 8 KiB blocks using algorithms such as zlib, LZ4, LZO, XZ, or Zstd.[1] The superblock, a fixed 96-byte structure at the beginning of the image, encodes essential filesystem parameters including the magic numbersqsh (0x73717368), major and minor version numbers, inode count, modification time, default block size (a power of 2 between 4 KiB and 1 MiB), compression method identifier, flags for features like uncompressed inodes or directories, and 64-bit offsets to the starts of the inode table, directory table, fragment table, lookup table, and extended attribute table.[1] These offsets facilitate navigation to metadata sections, while additional fields specify root inode location and compression options block presence.[11]
The inode table follows the superblock and consists of compressed 8 KiB metadata blocks, each prefixed by a 2-byte length field indicating the uncompressed size (with the high bit set if uncompressed).[1] Inodes are variable-length records averaging 8 bytes, identified by a 48-bit tuple of metadata block address and offset within it; each includes type (e.g., file, directory, symlink), permissions, UID/GID indices, modification time, and type-specific data such as file size, block list pointers for regular files (up to four direct 64-bit block addresses plus an indirect index for larger files), or directory start block and parent inode for directories.[1][11]
Directory tables are stored in similarly compressed 8 KiB metadata blocks and employ a two-level structure for efficient lookup: a header block containing the directory inode number, entry count (off-by-one), and start offset, followed by sorted entries in subsequent blocks, where each entry comprises a 2-byte offset, inode reference, type, name length (off-by-one), and null-terminated name string.[11] For larger directories, an optional index table provides binary search acceleration by listing up to 31 header locations with hash values.[1]
The fragment table, located after the directory table, handles the tail ends of regular files or entire small files smaller than the block size by packing them into shared 8 KiB compressed blocks; it comprises a sequence of metadata blocks with 12-byte entries per fragment, including a 64-bit start offset, 32-bit uncompressed size (high bit set if uncompressed), and padding.[1][11] File inodes reference fragments via a 32-bit index into this global table (with each file using at most one entry), allowing efficient storage without wasting full blocks. The table itself consists of multiple metadata blocks, each holding up to 512 entries.[1]
Version 3 of SquashFS, introduced earlier, supports filesystems up to 2^64 bytes and files up to approximately 2 TiB but uses 32-bit fields in some places, limiting certain offsets.[1] In contrast, version 4, released in 2009, enhances the layout with full 64-bit support throughout for offsets and sizes, enabling filesystems up to 2^64 bytes and theoretical file sizes up to 2^64 bytes (though practical limits due to kernel index caching restrict files to approximately 2 TiB), larger block sizes up to 1 MiB, and integrated extended attributes via a dedicated table referenced by inode offsets.[1][13] These changes in v4 also introduce compressor options as a separate block and refine metadata packing for better compression ratios.[11]
Compression Mechanisms
SquashFS employs block-based compression to store file data efficiently, dividing files into fixed-size blocks that are compressed individually using selected algorithms. This approach allows for random access to file contents without decompressing the entire filesystem, as each block can be decompressed on demand. Block sizes range from 4 KiB to 1 MiB, with the default being 128 KiB, enabling trade-offs between compression density and access overhead. For files smaller than the block size or with tail data not filling a full block, SquashFS uses compressed fragment blocks to pack multiple such remnants, referenced via a 32-bit index into the global fragment table (with each file using at most one entry).[1][14] The filesystem supports multiple compression algorithms integrated into its storage model: gzip (using zlib, the default for balanced performance), LZ4 (prioritizing fast decompression suitable for resource-constrained environments), LZO (offering speed similar to LZ4 with slightly better ratios), XZ and LZMA (providing high compression ratios at the cost of slower decompression), and Zstd (delivering a strong balance of ratio and speed). Each compressed block is prefixed with a two-byte header indicating its compressed length, and blocks that do not shrink upon compression are stored uncompressed to avoid overhead. The compression algorithm is specified globally in the superblock and applied uniformly to all data and metadata. Metadata such as inodes and directories is also compressed in 8 KiB blocks using the same algorithm.[1][14] To reduce redundancy, SquashFS implements file-level deduplication by detecting identical files during image creation and sharing their data blocks, storing the content only once while multiple inodes reference the same blocks. This occurs before compression, enhancing space savings across duplicate content like libraries or binaries in distributions. Per-block headers add minimal overhead—typically 2 bytes per block—while the overall metadata structure keeps inode sizes around 8 bytes on average, packed efficiently to minimize padding.[14][15] In terms of performance, gzip typically achieves approximately 3:1 compression ratios on mixed filesystem data, reducing ext3-sized images to about one-third their original size. LZ4 excels in decompression speed, often matching or exceeding uncompressed read rates on embedded hardware, though with lower ratios around 1.5:1 to 2:1. Zstd provides competitive ratios of 2:1 to 3:1 on typical binaries while supporting multi-threaded decompression for up to 2 threads per core, making it ideal for modern applications balancing storage and access speed.[4][16]Metadata Management
SquashFS manages file metadata through a highly compact and compressed structure designed for read-only storage efficiency. Metadata, including inodes, directories, and extended attributes, is stored in dedicated blocks that are compressed using algorithms such as zlib, LZ4, LZO, XZ, or Zstd, allowing for significant space savings while enabling fast access in kernel space.[1] This approach packs metadata on byte boundaries and optimizes formats based on file types to minimize overhead.[1] Inodes in SquashFS are the core metadata structures representing files, directories, symlinks, and devices, stored in compressed 8 KiB blocks prefixed by a 2-byte length field (with the top bit indicating if uncompressed). Each inode is identified by a 48-bit number comprising a block location and offset, facilitating precise retrieval. Basic inodes, optimized for common cases, are approximately 8 bytes and include essential fields like mode, UID/GID, timestamps, and block pointers for regular files. Extended inodes provide additional details, such as ACL support or extended attributes, with formats varying by type: regular files include fragment and extended timestamp fields (with 64-bit size for theoretical support up to 2^64 bytes, though practical limits are ~2 TiB), directories reference entry tables, symlinks store target paths, and devices hold major/minor numbers. These size-optimized formats ensure compact representation tailored to each file type.[1] Directory entries are organized within compressed 8 KiB metadata blocks forming a directory table, using a two-level structure for efficiency: a shared header block followed by an entry list. Entries are sorted alphabetically and include name offsets (up to 28 bits for length) and inode references, enabling compact storage. To accelerate lookups, SquashFS employs hashed indexing through directory index tables—one per metadata block—that allow the kernel to identify and decompress only the relevant block, avoiding full table scans and supporting fast pathname resolution even in large directories.[1] Extended attributes in SquashFS are handled via a separate compressed 8 KiB metadata table, where each inode references a 32-bit xattr ID for lookup. This ID maps to attribute entries that support both inline storage (for small values directly in the entry) and out-of-line storage (referencing deduplicated values in the table to reduce redundancy). The system accommodates security contexts, such as SELinux labels, by encoding prefixes like "security." in the type field, and user-defined data, enabling flexible metadata attachment without bloating inode sizes.[1] Metadata compression occurs in fixed 8 KiB blocks, similar to data blocks, but with options like -noI during image creation to store inodes uncompressed if beneficial. While general-purpose compressors are used, the packing and byte-aligned design inherently provides high ratios; blocks exceeding the compressed size may remain uncompressed for performance. This balances storage efficiency with quick decompression during access.[1] For access, the kernel resolves pathnames by iteratively reading and decompressing metadata blocks using inode and directory identifiers. Upon mount, metadata blocks are cached as needed, with directory indexes scanned linearly to locate entries, and inode details fetched via offsets for attribute retrieval, ensuring efficient in-memory representation without full filesystem loading.[1]Usage and Tools
Creating Images
SquashFS images are generated using the mksquashfs command-line utility, part of the squashfs-tools package developed and maintained by the SquashFS project.[5] This tool compresses a source directory or set of files into a single, read-only SquashFS filesystem image, suitable for embedding in larger systems or archival purposes.[12] The basic syntax for creating an image ismksquashfs [options] source1 [source2 ...] output, where sources can be directories or files, and output specifies the target filesystem file or block device.[12] For example, to create a compressed image from a source directory, the command mksquashfs /path/to/source /path/to/target.sqsh produces a file named target.sqsh containing the SquashFS image with default settings, including gzip compression and a 128 KB block size.[12]
Key options allow customization of the image creation process. Compression can be specified with -comp {gzip|lzo|xz|lz4|zstd|lzma}, where gzip is the default; for instance, -comp [zstd](/page/Zstd) enables Zstandard compression for potentially better ratios and speed.[12] The block size is set via -b BLOCK_SIZE (e.g., -b 1M for 1 MB blocks, up to a maximum of 1 MB), which influences compression efficiency and memory usage during creation—larger blocks generally improve ratios for sequential data but may increase overhead for random access.[12] Files or directories can be excluded using -ef exclude_file, where the file lists patterns to skip (e.g., temporary files like *.tmp), or multiple -e flags for inline lists, reducing image size by omitting unnecessary content.[12] Progress tracking is enabled with -info, which displays each file as it is processed, aiding in monitoring long operations.[12]
Advanced features enhance performance and optimization. Multithreaded compression is controlled by -processors N, where N specifies the number of CPU cores to use (defaulting to all available cores), significantly speeding up creation on multi-core systems—for example, -processors 4 limits to four threads.[12] For better compression ratios, files can be sorted prior to processing using -sort sort_file, where the sort_file contains paths with priority values (-32768 to 32767, default 0) to group similar files together, such as by type or modification time via a pre-generated list.[12]
Output can be directed to a regular file for portability or directly to a block device (e.g., /dev/sdb1) for in-place filesystem creation, though writing to devices requires appropriate permissions and caution to avoid data loss.[12] When targeting partitions or embedded storage, images should be padded to align with device block sizes, typically 1 MiB boundaries, as the Linux kernel requires this for mounting; this can be achieved post-creation using tools like dd to append zero bytes (e.g., dd if=/dev/zero of=target.sqsh bs=1M count=1 >> target.sqsh adjusted for size).[1] The resulting layout follows the standard SquashFS structure, with selectable compression algorithms applied to data blocks.[1]
Common error handling during image creation includes issues like permission denied (ensure read access to sources and write access to output), insufficient disk space (verify target location has enough free space, often several times the uncompressed source size during temporary operations), and invalid options such as unsupported block sizes or compression algorithms (check compatibility with the squashfs-tools version).[12] Out-of-memory errors may occur with very large sources or high block sizes on resource-constrained systems, resolvable by reducing parallelism or block size.[12]
Mounting and Extraction
SquashFS images are accessed in a running Linux system primarily through mounting, which integrates the compressed filesystem into the directory hierarchy as a read-only view. The standard method uses themount command with the -t squashfs option; for file-based images not on a block device, the -o [loop](/page/Loop) option enables loopback mounting to treat the file as a block device. For example, mount -t squashfs -o loop image.sqsh /mnt/point attaches the image at the specified mount point, assuming the SquashFS kernel module is loaded via [modprobe](/page/Modprobe) squashfs or compiled into the kernel.[9][17]
Once mounted, SquashFS operates with strict read-only semantics, where the kernel handles all file and directory reads by decompressing data blocks, inodes, and metadata on-the-fly using supported algorithms such as Zlib, LZ4, LZO, XZ, or Zstd. This decompression occurs transparently during access, with mount options like threads=multi allowing multi-threaded processing to distribute the workload across CPU cores for better performance. To optimize repeated accesses, the kernel maintains fixed caches for metadata (64 KiB), file fragments (1 MiB), and block indexes (64 KiB), reducing decompression overhead for frequently used data.[1]
For full extraction of SquashFS contents outside of a mounted view, the unsquashfs utility from the official squashfs-tools package unpacks the image to a target directory, decompressing all files, directories, and extended attributes. By default, it preserves original file permissions, timestamps, and xattrs via the -xattrs option, directing output to a subdirectory named squashfs-root unless overridden with -d /path/to/extract. Selective extraction is possible by specifying files or directories as arguments, and the -f flag forces overwrites of existing targets.[5][18]
To enable writable modifications atop a SquashFS image without altering the original, union mounts combine it with overlay filesystems such as OverlayFS or AUFS, using the SquashFS mount as the read-only lower layer and a writable directory (e.g., on tmpfs or disk) as the upper layer. For OverlayFS, this is achieved via mount -t overlay overlay -o lowerdir=/squashfs/mnt,upperdir=/writable/dir,workdir=/work/dir /merged/point, allowing changes to appear persistent in the merged view while leaving the base image intact.[19][20]
Key limitations of SquashFS access include its inherent read-only nature, prohibiting direct writes or modifications to the mounted image, which requires extraction or overlays for any changes. Decompression introduces performance overhead, particularly for random reads or large uncompressed files, though caching and threaded options mitigate this; for instance, single-threaded mode may bottleneck on multi-core systems, while per-CPU threading can scale better but increases memory use.[1]
Supporting Software
The SquashFS ecosystem relies on a suite of core user-space tools known as squashfs-tools, which are licensed under GPLv2 or later and include utilities such as mksquashfs for creating compressed filesystem images, unsquashfs for extracting them, and sqfstar for generating self-extracting archives.[5][21] These tools have been actively maintained on GitHub since 2015 by developer Phillip Lougher.[5] In the Linux kernel, SquashFS is supported as a built-in read-only filesystem module since version 2.6.29, configurable via the CONFIG_SQUASHFS kernel option, which enables support for various compression algorithms including Zstandard (Zstd).[1][22][23] Cross-platform compatibility extends beyond Linux, with ports available for FreeBSD through the sysutils/squashfs-tools package in its ports collection, allowing creation and extraction of SquashFS images.[24] On Windows, SquashFS images can be opened and extracted using 7-Zip, while custom builds of squashfs-tools provide native support; Android environments leverage squashfs-tools from the Android Open Source Project for image handling.[25][26] For programmatic access, libraries such as libsquash provide a portable user-space implementation of SquashFS that can be embedded in applications for reading and writing images without kernel dependencies.[27] SquashFS also integrates with archive tools like genisoimage, commonly used to embed SquashFS images within ISO files for bootable media.[28] Development remains active, with the latest squashfs-tools release, version 4.7.4 (November 2025), a bug-fix release following version 4.7.3 which incorporated optimizations for sparse file reading (up to 1500× speed improvement) and bug fixes addressing Zstd compression corruptions in iterative workflows.[29][30][31]Applications
Embedded Systems
SquashFS plays a pivotal role in embedded systems, particularly in resource-constrained environments such as routers and Internet of Things (IoT) devices, where storage efficiency and reliability are paramount. Its compressed, read-only nature makes it ideal for firmware images stored on limited flash memory, allowing developers to pack essential system components into small footprints without sacrificing accessibility.[32] By leveraging compression algorithms like LZ4, LZO, or XZ, SquashFS achieves significant space savings in firmware size, enabling deployment on smaller flash storage ranging from 4 to 16 MB. For instance, in a Texas Instruments embedded system, a root filesystem uncompressed to 121 MB was reduced to just 7.8 MB using SquashFS, demonstrating substantial efficiency for mixed content including binaries and configuration files. This reduction is particularly beneficial for kernel modules and binaries, which often exhibit good compression depending on the algorithm and block size, as larger blocks enhance ratios for repetitive binary data while maintaining quick decompression.[33][34] Prominent examples include OpenWrt distributions for routers, where SquashFS serves as the default root filesystem to fit within constrained NOR or NAND flash on devices like those with 8-32 MB storage. In IoT applications, such as smart home gateways or industrial sensors, SquashFS is commonly used for immutable firmware to minimize storage demands and ensure consistent operation across deployments.[32][35] Key benefits in these contexts include fast boot times enabled by on-demand decompression, which avoids loading the entire image into memory upfront, and inherent immutability that enhances system reliability by preventing runtime modifications that could lead to corruption on flash hardware. This read-only design aligns well with the persistent, non-volatile needs of embedded hardware, reducing wear on flash through minimized write cycles.[34][20] However, SquashFS's read-only limitation presents challenges for embedded systems requiring updates; changes necessitate either full firmware image flashes, which can be time-consuming on low-bandwidth connections, or the use of overlay filesystems like OverlayFS to provide a writable layer atop the compressed base. In practice, many embedded Linux setups combine SquashFS for the base rootfs with an overlay for configuration and logs, balancing immutability with flexibility.[20]Live Media
SquashFS serves a critical role in live CDs and DVDs by enabling the creation of compact, bootable ISO images for operating system installations and rescue environments, where the bulk of the filesystem is stored as a compressed, read-only archive. Distributions such as Ubuntu employ SquashFS to package the root filesystem into a singlefilesystem.squashfs file within the ISO, achieving significant size reductions—for instance, compressing multi-gigabyte OS trees to under 2 GB, which fits on standard optical media while preserving fast access times.[36][1]
The boot process for these live media typically starts with an initial RAM disk (initrd or initramfs) that loads a minimal kernel along with essential drivers and boot scripts. Once hardware detection is complete, the SquashFS image is mounted in loopback mode as the read-only root filesystem, overlaid with a tmpfs instance in RAM to provide writable layers for session-specific changes, leveraging union mount techniques for seamless read-write functionality.[37][38]
Prominent examples include Debian Live, which uses SquashFS for its hybrid ISO images and offers persistence options through dedicated partitions or filesystems labeled "persistence" to retain user data and configurations across reboots. Fedora LiveOS similarly relies on a squashfs.img file containing the compressed root, with the Fedora Media Writer tool streamlining the process of writing these images to USB drives for portable booting.[37][38][39]
Key advantages of SquashFS in this context include high portability, as the media can boot and run the OS without any host installation or disk modifications, and its compression efficiency, which permits inclusion of extensive software suites on media limited to 700 MB CDs or 4.7 GB DVDs.[9][1]
Over time, live media has shifted from earlier compressed formats like CramFS to SquashFS, driven by the latter's improved compression.[34]
Modern Packaging Formats
SquashFS has been integrated into several modern packaging formats for software distribution, leveraging its compressed read-only nature to bundle applications and dependencies efficiently. In AppImage, a format for creating portable Linux applications, the file system image is built using SquashFS to encapsulate the application's binaries, libraries, and other dependencies within a single executable file. This allows users to run the application directly without installation, as the runtime component mounts the SquashFS image via FUSE to access the bundled contents on demand.[40] Snap packages, developed by Canonical, employ SquashFS as the core of their read-only assertion layer, where the entire snap is stored as a compressed SquashFS archive mounted at/snap/<snap name>/<revision>/. This design ensures immutable content delivery, preventing modifications to the core files while supporting writable overlays for user data and configuration through paths like $SNAP_USER_DATA. The combination facilitates secure, versioned updates without risking system integrity.[41]
In container technologies adhering to the Open Container Initiative (OCI) standards, SquashFS is utilized in formats like OCI-SIF to compress root filesystems into a single layer, enhancing compatibility with tools such as Docker and Podman. For instance, when pulling an OCI image with Apptainer (formerly Singularity), the multi-layer structure is squashed into a SquashFS-based single file, reducing storage overhead while maintaining OCI interoperability for base layers. This approach is particularly beneficial for high-performance computing environments where compressed roots minimize transfer times and disk usage.[42]
Android's over-the-air (OTA) update mechanism supports SquashFS as an alternative filesystem for A/B seamless updates, where it can be used to create compressed read-only images for the /system and /vendor partitions. This enables efficient delivery of updates by shipping pre-optimized artifacts directly in the image, equivalent in storage efficiency to ext4-based setups but with added compression benefits for bandwidth-constrained devices.[43]
The adoption of SquashFS in these formats provides key advantages, including atomic updates through its immutable read-only structure, which ensures that changes are applied entirely or not at all, minimizing partial failure risks. Compression significantly reduces bandwidth requirements for distribution, as seen in snap and AppImage downloads, while the read-only enforcement enhances security by limiting runtime tampering opportunities, often complemented by extended attributes for access controls.[1]