Fiemap Ioctl¶
The fiemap ioctl is an efficient method for userspace to get fileextent mappings. Instead of block-by-block mapping (such as bmap), fiemapreturns a list of extents.
Request Basics¶
A fiemap request is encoded withinstructfiemap:
- structfiemap¶
file extent mappings
Definition:
struct fiemap { __u64 fm_start; __u64 fm_length; __u32 fm_flags; __u32 fm_mapped_extents; __u32 fm_extent_count; struct fiemap_extent fm_extents[];};Members
fm_startbyte offset (inclusive) at which to start mapping (in)
fm_lengthlogical length of mapping which userspace wants (in)
fm_flagsFIEMAP_FLAG_* flags for request (in/out)
fm_mapped_extentsnumber of extents that were mapped (out)
fm_extent_countsize of fm_extents array (in)
fm_extentsarray of mapped extents (out)
fm_start, and fm_length specify the logical range within the filewhich the process would like mappings for. Extents returned mirrorthose on disk - that is, the logical offset of the 1st returned extentmay start before fm_start, and the range covered by the last returnedextent may end after fm_length. All offsets and lengths are in bytes.
Certain flags to modify the way in which mappings are looked up can beset in fm_flags. If the kernel doesn’t understand some particularflags, it will return EBADR and the contents of fm_flags will containthe set of flags which caused the error. If the kernel is compatiblewith all flags passed, the contents of fm_flags will be unmodified.It is up to userspace to determine whether rejection of a particularflag is fatal to its operation. This scheme is intended to allow thefiemap interface to grow in the future but without losingcompatibility with old software.
fm_extent_count specifies the number of elements in the fm_extents[] arraythat can be used to return extents. If fm_extent_count is zero, then thefm_extents[] array is ignored (no extents will be returned), and thefm_mapped_extents count will hold the number of extents needed infm_extents[] to hold the file’s current mapping. Note that there isnothing to prevent the file from changing between calls to FIEMAP.
The following flags can be set in fm_flags:
- FIEMAP_FLAG_SYNC
If this flag is set, the kernel will sync the file before mapping extents.
- FIEMAP_FLAG_XATTR
If this flag is set, the extents returned will describe the inodesextended attribute lookup tree, instead of its data tree.
- FIEMAP_FLAG_CACHE
This flag requests caching of the extents.
Extent Mapping¶
Extent information is returned within the embedded fm_extents arraywhich userspace must allocate along with the fiemap structure. Thenumber of elements in the fiemap_extents[] array should be passed viafm_extent_count. The number of extents mapped by kernel will bereturned via fm_mapped_extents. If the number of fiemap_extentsallocated is less than would be required to map the requested range,the maximum number of extents that can be mapped in the fm_extent[]array will be returned and fm_mapped_extents will be equal tofm_extent_count. In that case, the last extent in the array will notcomplete the requested range and will not have the FIEMAP_EXTENT_LASTflag set (see the next section on extent flags).
Each extent is described by a single fiemap_extent structure asreturned in fm_extents:
- structfiemap_extent¶
description of one fiemap extent
Definition:
struct fiemap_extent { __u64 fe_logical; __u64 fe_physical; __u64 fe_length; __u32 fe_flags;};Members
fe_logicalbyte offset of the extent in the file
fe_physicalbyte offset of extent on disk
fe_lengthlength in bytes for this extent
fe_flagsFIEMAP_EXTENT_* flags for this extent
All offsets and lengths are in bytes and mirror those on disk. It is validfor an extents logical offset to start before the request or its logicallength to extend past the request. Unless FIEMAP_EXTENT_NOT_ALIGNED isreturned, fe_logical, fe_physical, and fe_length will be aligned to theblock size of the file system. With the exception of extents flagged asFIEMAP_EXTENT_MERGED, adjacent extents will not be merged.
The fe_flags field contains flags which describe the extent returned.A special flag, FIEMAP_EXTENT_LAST is always set on the last extent inthe file so that the process making fiemap calls can determine when nomore extents are available, without having to call the ioctl again.
Some flags are intentionally vague and will always be set in thepresence of other more specific flags. This way a program looking fora general property does not have to know all existing and future flagswhich imply that property.
For example, if FIEMAP_EXTENT_DATA_INLINE or FIEMAP_EXTENT_DATA_TAILare set, FIEMAP_EXTENT_NOT_ALIGNED will also be set. A program lookingfor inline or tail-packed data can key on the specific flag. Softwarewhich simply cares not to try operating on non-aligned extentshowever, can just key on FIEMAP_EXTENT_NOT_ALIGNED, and not have toworry about all present and future flags which might imply unaligneddata. Note that the opposite is not true - it would be valid forFIEMAP_EXTENT_NOT_ALIGNED to appear alone.
- FIEMAP_EXTENT_LAST
This is generally the last extent in the file. A mapping attempt pastthis extent may return nothing. Some implementations set this flag toindicate this extent is the last one in the range queried by the user(via fiemap->fm_length).
- FIEMAP_EXTENT_UNKNOWN
The location of this extent is currently unknown. This may indicatethe data is stored on an inaccessible volume or that no storage hasbeen allocated for the file yet.
- FIEMAP_EXTENT_DELALLOC
This will also set FIEMAP_EXTENT_UNKNOWN.
Delayed allocation - while there is data for this extent, itsphysical location has not been allocated yet.
- FIEMAP_EXTENT_ENCODED
This extent does not consist of plain filesystem blocks but isencoded (e.g. encrypted or compressed). Reading the data in thisextent via I/O to the block device will have undefined results.
Note that it isalways undefined to try to update the datain-place by writing to the indicated location without theassistance of the filesystem, or to access the data using theinformation returned by the FIEMAP interface while the filesystemis mounted. In other words, user applications may only read theextent data via I/O to the block device while the filesystem isunmounted, and then only if the FIEMAP_EXTENT_ENCODED flag isclear; user applications must not try reading or writing to thefilesystem via the block device under any other circumstances.
- FIEMAP_EXTENT_DATA_ENCRYPTED
This will also set FIEMAP_EXTENT_ENCODEDThe data in this extent has been encrypted by the file system.
- FIEMAP_EXTENT_NOT_ALIGNED
Extent offsets and length are not guaranteed to be block aligned.
- FIEMAP_EXTENT_DATA_INLINE
This will also set FIEMAP_EXTENT_NOT_ALIGNEDData is located within a meta data block.
- FIEMAP_EXTENT_DATA_TAIL
This will also set FIEMAP_EXTENT_NOT_ALIGNEDData is packed into a block with data from other files.
- FIEMAP_EXTENT_UNWRITTEN
Unwritten extent - the extent is allocated but its data has not beeninitialized. This indicates the extent’s data will be all zero if readthrough the filesystem but the contents are undefined if read directly fromthe device.
- FIEMAP_EXTENT_MERGED
This will be set when a file does not support extents, i.e., it uses a blockbased addressing scheme. Since returning an extent for each block back touserspace would be highly inefficient, the kernel will try to merge mostadjacent blocks into ‘extents’.
- FIEMAP_EXTENT_SHARED
This flag is set to request that space be shared with other files.
VFS -> File System Implementation¶
File systems wishing to support fiemap must implement a ->fiemap callback ontheir inode_operations structure. The fs ->fiemap call is responsible fordefining its set of supported fiemap flags, and calling a helper function oneach discovered extent:
struct inode_operations { ... int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len);->fiemap is passedstructfiemap_extent_info which describes thefiemap request:
- structfiemap_extent_info¶
fiemap request to a filesystem
Definition:
struct fiemap_extent_info { unsigned int fi_flags; unsigned int fi_extents_mapped; unsigned int fi_extents_max; struct fiemap_extent __user *fi_extents_start;};Members
fi_flagsFlags as passed from user
fi_extents_mappedNumber of mapped extents
fi_extents_maxSize of fiemap_extent array
fi_extents_startStart of fiemap_extent array
It is intended that the file system should not need to access any of thisstructure directly. Filesystem handlers should be tolerant to signals and returnEINTR once fatal signal received.
Flag checking should be done at the beginning of the ->fiemap callback via thefiemap_prep() helper:
int fiemap_prep(struct inode *inode, struct fiemap_extent_info *fieinfo, u64 start, u64 *len, u32 supported_flags);
Thestructfieinfo should be passed in as received fromioctl_fiemap(). Theset of fiemap flags which the fs understands should be passed via fs_flags. Iffiemap_prep finds invalid user flags, it will place the bad values infieinfo->fi_flags and return -EBADR. If the file system gets -EBADR, fromfiemap_prep(), it should immediately exit, returning that error back toioctl_fiemap(). Additionally the range is validate against the supportedmaximum file size.
For each extent in the request range, the file system should callthe helper function,fiemap_fill_next_extent():
int fiemap_fill_next_extent(struct fiemap_extent_info *info, u64 logical, u64 phys, u64 len, u32 flags, u32 dev);
fiemap_fill_next_extent() will use the passed values to populate thenext free extent in the fm_extents array. ‘General’ extent flags willautomatically be set from specific flags on behalf of the calling filesystem so that the userspace API is not broken.
fiemap_fill_next_extent() returns 0 on success, and 1 when theuser-supplied fm_extents array is full. If an error is encounteredwhile copying the extent to user memory, -EFAULT will be returned.