In am trying to understand how to calculate a sector number from an inode in the ext4 filesystem. Therefore, I am reading ext4_mpage_readpages function.

About the function: During a read request, if the page is not found in the page cache, a new page is allocated and added to the page cache. After that, the above function is called to get the data from the disk and fill it in the page.

I know that the size of a page is 4096 bytes, and that blocks are of 512 bytes (therefore, a page consists of 8 blocks). From what I understood, the above function maps the block numbers to pages in blocks[page_block] at these places: here and here. After mapping the blocks, the function allocates a bio, assigns the sector to read from, and calls the generic_make_request() to read the data from the disk.

I am getting confused in understanding how the above function calculates sector given an address_space mapping. Is there any other way to get a sector number from an inode in ext4 filesystem?

  • This guide explains the format, so you can make calculations. (Thanks @StephenKitt for link update). If you just want the result without doing all the work yourself, the debugfs utility can help. – Wumpus Q. Wumbley Apr 24 at 12:19

The easiest way to do this is running the command filefrag -v /path/to/file which can be run as a regular user (unlike debugfs which needs read access to the block device, typically only for root). This will give you ext4 physical block numbers (typically 4096 bytes) relative to the start of the partition for the corresponding logical offset within the file. You can also use filefrag -v -k for units of KiB or filefrag -v -b1 for 1-byte "blocks".

$ filefrag -vb1 google-chrome-stable_current_x86_64.rpm 
Filesystem type is: ef53
File size of google-chrome-stable_current_x86_64.rpm is 57333190
     (57335808 blocks of 1 bytes)
 ext:     logical_offset:        physical_offset: length:   expected: flags:
   0:        0.. 8388607: 5872025600..5880414207: 8388608: 
   1:  8388608..16777215: 5897191424..5905580031: 8388608: 5880414208:
   2: 16777216..25165823: 6241124352..6249512959: 8388608: 5905580032:
   3: 25165824..33554431: 8019509248..8027897855: 8388608: 6249512960:
   4: 33554432..41943039: 8128561152..8136949759: 8388608: 8027897856:
   5: 41943040..50331647: 8220835840..8229224447: 8388608: 8136949760:
   6: 50331648..57335807: 28538081280..28545085439: 7004160: 8229224448: last,eof

This is using ioctl(fd, FS_IOC_FIEMAP, ...) to request the extent mapping for the file descriptor, which in turn uses the ->fiemap() method of most common filesystems. Much older kernels used ioctl(fd, FS_IOC_FIBMAP, ...) but it can only map a single block at a time, and may require millions of calls for large files today.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.