Skip to content

File Systems and Mounting

The Virtual File System layer is the kernel abstraction that allows Linux to support multiple file System types simultaneously. Application code calls open(2)``read(2)``write(2)And stat(2) Without knowing whether the underlying storage uses ext4, XFS, Btrfs, NFS, or a pseudo-filesystem Like procfs.

graph TD
    A[User Space Applications] -->|open, read, write| B[System Call Interface]
    B --> C[VFS Layer]
    C --> D[ext4]
    C --> E[XFS]
    C --> F[Btrfs]
    C --> G[NFS / CIFS]
    C --> H[tmpfs / procfs / sysfs]
    C --> I[FUSE]
    D --> J[Block Device Layer]
    E --> J
    F --> J
    G --> K[Network Stack]
    H --> L[Memory / Kernel]
    I --> M[User-Space Daemon]
    J --> N[Physical Storage]

The VFS maintains four primary object types:

ObjectDescriptionKernel Type
superblockDescribes a mounted file system (type, size, flags)struct super_block
inodeRepresents a single file (metadata: permissions, size, timestamps)struct inode
dentryDirectory entry — maps a name to an inodestruct dentry
fileRepresents an open file (current offset, access mode)struct file

The dentry cache (dcache) holds the directory hierarchy in memory, avoiding disk lookups for Frequently accessed paths. The inode cache (icache) keeps recently accessed inodes in memory. Both Caches are critical for performance — a warm dentry cache means stat(2) on a file requires no disk I/O.

Each file system type registers with the VFS using register_filesystem(). The registration Includes a struct file_system_type that provides:

  • Name (e.g., “ext4”, “xfs”, “btrfs”)
  • Mount function pointer
  • Kill superblock function pointer
  • Module owner (for loadable modules)

When mount(2) is called, the VFS invokes the appropriate file system”s mount function, which reads The superblock from disk and populates the VFS superblock object.

An inode (index node) is the fundamental data structure representing a file on disk. It contains all Metadata about a file except the filename (which is stored in the directory’s data blocks, not in The inode itself).

FieldDescription
st_modeFile type and permissions (16 bits)
st_inoInode number (unique within file system)
st_devDevice number (identifies the file system)
st_nlinkHard link count
st_uidOwner user ID
st_gidOwner group ID
st_sizeFile size in bytes (for regular files)
st_blksizePreferred block size for I/O
st_blocksNumber of 512-byte blocks allocated
st_atimLast access time (can be disabled with noatime)
st_mtimLast modification time (data change)
st_ctimLast status change time (metadata change)

A hard link is an additional directory entry pointing to the same inode. The inode’s link Count (st_nlink) tracks how many directory entries reference it. When the link count reaches zero And no process has the file open, the inode and its data blocks are freed.

Terminal window
# Demonstrate hard links
echo "content" > file1.txt
ln file1.txt file2.txt # hard link
ln -s file1.txt file3.txt # symbolic link
stat file1.txt
# Inode: 123456 Links: 2
stat file2.txt
# Inode: 123456 Links: 2 (same inode)
stat file3.txt
# Inode: 789012 Links: 1 (different inode — symlink)

The file type is encoded in the upper bits of st_mode:

OctalTypeDescription
010000Regular fileNormal data file
004000DirectoryContains directory entries
012000Symbolic linkPointer to another file
001000FIFO (named pipe)Inter-process communication
006000Block deviceBuffered access (e.g., /dev/sda)
002000Character deviceUnbuffered access (e.g., /dev/null)
014000SocketNetwork communication endpoint
Terminal window
# Test file types
[ -f file ] # regular file
[ -d dir ] # directory
[ -L link ] # symbolic link
[ -p pipe ] # named pipe
[ -b dev ] # block device
[ -c dev ] # character device
[ -S socket ] # socket
# Using stat
stat -c '%F' /dev/null # "character special file"
stat -c '%F' /dev/sda # "block special file"

Ext4 is the default file system on most Linux distributions. It is the evolutionary successor to Ext2 and ext3, adding extents, larger volumes, journal checksumming, and delayed allocation.

Featureext4 Details
Max volume size1 EiB (2^64 bytes theoretical, 64 TiB practical)
Max file size16 TiB
Max files~4 billion
Block sizes1024, 2048, 4096 bytes
JournalingOrdered mode (default), writeback, journal
AllocationExtents (replaces indirect block mapping)
ChecksumsJournal checksums, metadata checksums (metadata_csum)
Timestampsnanosecond granularity

Traditional ext2/ext3 used indirect block mapping — the inode pointed to a block of pointers, which Could point to more pointer blocks (up to 3 levels of indirection). This was inefficient for large Files because even a contiguous file required multiple block pointer lookups.

Ext4 introduces extents — a descriptor that maps a contiguous range of blocks. An extent can Describe up to 128 MiB of contiguous data in a single descriptor. For most files, the extent tree Fits entirely within the inode (no separate extent block needed).

Extent descriptor:
[logical_block, physical_block, length]
[0, 1000, 100] → blocks 0-99 mapped to disk blocks 1000-1099

Ext4 uses a journal to ensure file system consistency after a crash. The journal records metadata Changes (and optionally data changes) before committing them to the main file system.

Journal ModeWhat is JournaledPerformanceSafety
ordered (default)Metadata only (data written before metadata committed)GoodHigh
writebackMetadata only (no ordering guarantee)BestMedium
journalBoth metadata and dataSlowestHighest
Terminal window
# View current journal mode
tune2fs -l /dev/sda1 | grep "Default mount options"
# Set journal mode (in /etc/fstab or tune2fs)
mount -o data=journal /dev/sda1 /mnt

Ext4 uses delayed allocation (delalloc): when a process writes data, the blocks are not Immediately allocated on disk. Instead, the data is held in memory, and allocation is deferred until The kernel flushes it. This allows the allocator to make better decisions about contiguous block Placement, significantly reducing fragmentation.

The downside: a crash before flush can lose more data than with immediate allocation. For databases That manage their own I/O (MySQL, PostgreSQL), delayed allocation should be disabled:

Terminal window
# Disable delayed allocation for database volumes
mount -o nodelalloc /dev/sdb1 /var/lib/mysql
# or in /etc/fstab:
# /dev/sdb1 /var/lib/mysql ext4 defaults,nodelalloc 0 2
Terminal window
# Reserve blocks for root (default 5%)
tune2fs -m 1 /dev/sda1 # reduce to 1%
# Enable directory indexing
tune2fs -O dir_index /dev/sda1
# Enable large file support
tune2fs -O large_file /dev/sda1
# Enable 64-bit mode (required for volumes > 16 TiB)
tune2fs -O 64bit /dev/sda1
# Check file system (must be unmounted or read-only)
e2fsck -f /dev/sda1
# View file system parameters
tune2fs -l /dev/sda1
dumpe2fs /dev/sda1
# Resize ext4 (can be done online for grow, offline for shrink)
resize2fs /dev/sda1 500G # grow to 500 GiB

XFS is a high-performance journaling file system developed by SGI in 1993, designed for parallel I/O And large files. It is the default on RHEL/CentOS 7+ and is well-suited for large data volumes, Media workloads, and databases.

FeatureXFS Details
Max volume size16 EiB (8 EiB on 32-bit systems)
Max file size8 EiB
Max filesPractically unlimited (based on space)
Block sizes512 to 65536 bytes (must be a power of 2, page-aligned)
JournalingMetadata-only journal (separate log device supported)
AllocationB+tree-based extent allocation
Allocation GroupsIndependent regions for parallel allocation

An XFS file system is divided into Allocation Groups (AGs), each of which manages its own free Space and inodes independently. This design enables parallel I/O — multiple processes can allocate Blocks in different AGs simultaneously without lock contention.

Terminal window
# View allocation group information
xfs_info /dev/sdb1
# agcount=4, agsize=... (4 allocation groups)
# AG count is automatically calculated based on volume size:
# Volume < 1 GiB: 1 AG
# Volume < 4 GiB: 4 AGs
# Volume < 16 GiB: 8 AGs
# Volume < 64 GiB: 16 AGs
# Volume < 256 GiB: 32 AGs
# etc.

XFS uses B+trees extensively for its internal data structures:

  • Inode B+tree: Maps inode numbers to inode locations within AGs
  • Free space B+tree: Tracks free extents within each AG (by block number and by extent length)
  • Extent B+tree: Maps file offsets to disk extents (for files with more than 4 extents)

B+trees are preferred over B-trees because all data is stored in leaf nodes, and internal nodes Contain only keys. This means each internal node can hold more keys, reducing tree depth and the Number of disk seeks required for lookups.

Aspectext4XFS
Volume resizeCan grow online, shrink offlineCan grow online, cannot shrink
Metadata repaire2fsck (can be slow)xfs_repair (fast but requires free space)
Delete performanceGoodExcellent (delayed allocation of AGs)
Large filesGoodExcellent (designed for large files)
Small filesBetterGood (more metadata overhead)
FragmentationMore susceptibleLess (extents + AGs)
SnapshotsNo native supportNo native support (use LVM/Btrfs)
Terminal window
# Create XFS with specific options
mkfs.xfs -f -b size=4096 -d agcount=8 -l size=512m /dev/sdb1
# View XFS parameters
xfs_info /mount/point
# Grow XFS (online, no shrink possible)
xfs_growfs /mount/point
# Repair XFS (must be unmounted)
xfs_repair /dev/sdb1
# Freeze/thaw file system (for consistent snapshots)
xfs_freeze -f /mount/point
# ... take snapshot ...
xfs_freeze -u /mount/point
# Defragment a file
xfs_fsr /mount/point/path/to/file