Logo
Fiemap: Efficient File Extent Mapping
Overview

Fiemap: Efficient File Extent Mapping

September 25, 2025
4 min read

Background

Before we dive into Fiemap, let’s quickly review some filesystem concepts:

ioctl()

ioctl() 함수란 하드웨어의 제어와 상태 정보를 얻기 위해 제공되는 함수

ioctl() stands for “input/output control” system call. It is method for a user application to send a control command directly to the kernel or device driver. It takes a file descriptor, a request code, and an optional argument (integer or pointer to a data structure), and returns an integer status code.

ioctl() vs read()/write():

  • ioctl() is used for device-specific operations and configurations. For example, it can be used to change device settings, get device status, or perform operations that are not standard file I/O.

  • read() and write() are used to transfer the file’s data between the kernel and user space. (i.e. only for reading/writing file content)

  • Linux Manual Page

Extent

Extent is a contiguous block of storage in a filesystem. An extent is defined by:

  • Starting Block: The first block of the extent; where it starts on the disk.
  • Logical Offset: The starting point of the extent within the file; where it starts in the file.
  • Length: The number of contiguous blocks in the extent.

Why Extents?

File systems, like ext4, XFS, and Btrfs, try to store files in contiguous blocks due to:

  1. Efficiency: Need to seek fewer blocks = faster read/write.
  2. Simplicity: Easier to manage fewer, larger blocks than many small ones.

Instead of tracking every single block, the filesystem tracks extents, which are ranges of contiguous blocks. This reduces metadata overhead and improves performance.

What is Fiemap?

Fiemap Documentation

Fiemap is a Linux ioctl interface that tells the user how a file is laid out on a disk. It returns the extents of a file, which contains a mapping from the file’s logical offsets to its physical disk blocks. Essentially, it shows where the data physically resides on the storage device.

Why Fiemap?

Due to fragmentation or file system behaviour, the data of a file may not be stored in a single contiguous block. Fiemap gives the programmer insight into how the file is actually stored on disk.

How to Use Fiemap

#include <linux/fiemap.h>
ioctl(fd, FS_IOC_FIEMAP, &fiemap);

Input:

  • fd: File descriptor of the file to be queried.
  • FS_IOC_FIEMAP: The ioctl command to request file extent mapping.
  • &fiemap: Pointer to a fiemap structure that will be filled with the extent information.

Output:

  • On success, the fiemap structure is populated with the file’s extent information.
  • On failure, it returns -1 and sets errno.

Structure of Fiemap Request

struct fiemap {
__u64 fm_start; /* logical offset (inclusive) at which to start mapping (in) */
__u64 fm_length; /* logical length of mapping which userspace cares about (in) */
__u32 fm_flags; /* FIEMAP_FLAG_* flags for request (in/out) */
__u32 fm_mapped_extents; /* number of extents that were mapped (out) */
__u32 fm_extent_count; /* size of fm_extents array (in) */
__u32 fm_reserved;
struct fiemap_extent fm_extents[0]; /* array of mapped extents (out)*/
};

Extent Mapping

The extent information is returned within the fiemap_extent array that the user allocates along with the fiemap structure. Each extent is described by a single fiemap_extent structure:

struct fiemap_extent {
__u64 fe_logical; /* logical offset in bytes for the start of the extent */
__u64 fe_physical; /* physical offset in bytes for the start of the extent */
__u64 fe_length; /* length in bytes for the extent */
__u64 fe_reserved64[2];
__u32 fe_flags; /* FIEMAP_EXTENT_* flags for this extent */
__u32 fe_reserved[3];
};

Code Example

Here is a simple example of how to use Fiemap to get the extent mapping of a file:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <linux/fiemap.h>
#include <errno.h>
#include <string.h>
#define EXTENTS_MAX 64 // how many extents we want to retrieve
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: %s <filename>\n", argv[0]);
exit(1);
}
const char *path = argv[1];
int fd = open(path, O_RDONLY);
if (fd < 0) {
perror("open");
exit(1);
}
// allocate fiemap structure with room for EXTENTS_MAX extents
size_t fiemap_size = sizeof(struct fiemap) +
EXTENTS_MAX * sizeof(struct fiemap_extent);
struct fiemap *fiemap = (struct fiemap *)calloc(1, fiemap_size);
if (!fiemap) {
perror("calloc");
close(fd);
exit(1);
}
fiemap->fm_start = 0; // start of file
fiemap->fm_length = ~0ULL; // map entire file
fiemap->fm_extent_count = EXTENTS_MAX; // request up to EXTENTS_MAX extents
if (ioctl(fd, FS_IOC_FIEMAP, fiemap) < 0) {
perror("ioctl(FS_IOC_FIEMAP)");
free(fiemap);
close(fd);
exit(1);
}
printf("File: %s\n", path);
printf("Mapped %u extents\n", fiemap->fm_mapped_extents);
for (unsigned int i = 0; i < fiemap->fm_mapped_extents; i++) {
struct fiemap_extent *ex = &fiemap->fm_extents[i];
printf("Extent %u: logical=%llu, physical=%llu, length=%llu, flags=0x%x\n",
i,
(unsigned long long)ex->fe_logical,
(unsigned long long)ex->fe_physical,
(unsigned long long)ex->fe_length,
ex->fe_flags);
}
free(fiemap);
close(fd);
return 0;
}

Output:

Terminal window
root@6a914391cd46:~# ./fiemap_example file.txt
File: file.txt
Mapped 1 extents
Extent 0: logical=0, physical=1337966592, length=12288, flags=0x1