fs/mpage.c
Source file repositories/reference/linux-study-clean/fs/mpage.c
File Facts
- System
- Linux kernel
- Corpus path
fs/mpage.c- Extension
.c- Size
- 19583 bytes
- Lines
- 694
- Domain
- Core OS
- Bucket
- VFS And Filesystem Core
- Inferred role
- Core OS: exported/initcall integration point
- Status
- integration implementation candidate
Why This File Exists
Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.
- Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.
- Exports symbols or registers init work; inspect boot/module ordering and who consumes the exported contract.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/kernel.hlinux/export.hlinux/mm.hlinux/kdev_t.hlinux/gfp.hlinux/bio.hlinux/fs.hlinux/buffer_head.hlinux/blkdev.hlinux/highmem.hlinux/prefetch.hlinux/mpage.hlinux/mm_inline.hlinux/writeback.hlinux/backing-dev.hinternal.h
Detected Declarations
struct mpage_readpage_argsstruct mpage_datafunction Copyrightfunction mpage_write_end_iofunction bio_for_each_folio_allfunction map_buffer_to_foliofunction buffer_mappedfunction mpage_readaheadfunction mpage_read_foliofunction clean_buffersfunction mpage_write_foliofunction mpage_write_folioexport mpage_readaheadexport mpage_read_folioexport __mpage_writepages
Annotated Snippet
struct mpage_readpage_args {
struct bio *bio;
struct folio *folio;
unsigned int nr_pages;
bool is_readahead;
sector_t last_block_in_bio;
struct buffer_head map_bh;
unsigned long first_logical_block;
get_block_t *get_block;
};
/*
* This is the worker routine which does all the work of mapping the disk
* blocks and constructs largest possible bios, submits them for IO if the
* blocks are not contiguous on the disk.
*
* We pass a buffer_head back and forth and use its buffer_mapped() flag to
* represent the validity of its disk mapping and to decide when to do the next
* get_block() call.
*/
static void do_mpage_readpage(struct mpage_readpage_args *args)
{
struct folio *folio = args->folio;
struct inode *inode = folio->mapping->host;
const unsigned blkbits = inode->i_blkbits;
const unsigned blocks_per_folio = folio_size(folio) >> blkbits;
const unsigned blocksize = 1 << blkbits;
struct buffer_head *map_bh = &args->map_bh;
sector_t block_in_file;
sector_t last_block;
sector_t last_block_in_file;
sector_t first_block;
unsigned page_block;
unsigned first_hole = blocks_per_folio;
struct block_device *bdev = NULL;
int length;
int fully_mapped = 1;
blk_opf_t opf = REQ_OP_READ;
unsigned nblocks;
unsigned relative_block;
gfp_t gfp = mapping_gfp_constraint(folio->mapping, GFP_KERNEL);
if (args->is_readahead) {
opf |= REQ_RAHEAD;
gfp |= __GFP_NORETRY | __GFP_NOWARN;
}
if (folio_buffers(folio))
goto confused;
block_in_file = folio_pos(folio) >> blkbits;
last_block = block_in_file + ((args->nr_pages * PAGE_SIZE) >> blkbits);
last_block_in_file = (i_size_read(inode) + blocksize - 1) >> blkbits;
if (last_block > last_block_in_file)
last_block = last_block_in_file;
page_block = 0;
/*
* Map blocks using the result from the previous get_blocks call first.
*/
nblocks = map_bh->b_size >> blkbits;
if (buffer_mapped(map_bh) &&
block_in_file > args->first_logical_block &&
block_in_file < (args->first_logical_block + nblocks)) {
unsigned map_offset = block_in_file - args->first_logical_block;
unsigned last = nblocks - map_offset;
first_block = map_bh->b_blocknr + map_offset;
for (relative_block = 0; ; relative_block++) {
if (relative_block == last) {
clear_buffer_mapped(map_bh);
break;
}
if (page_block == blocks_per_folio)
break;
page_block++;
block_in_file++;
}
bdev = map_bh->b_bdev;
}
/*
* Then do more get_blocks calls until we are done with this folio.
*/
map_bh->b_folio = folio;
while (page_block < blocks_per_folio) {
map_bh->b_state = 0;
map_bh->b_size = 0;
if (block_in_file < last_block) {
Annotation
- Immediate include surface: `linux/kernel.h`, `linux/export.h`, `linux/mm.h`, `linux/kdev_t.h`, `linux/gfp.h`, `linux/bio.h`, `linux/fs.h`, `linux/buffer_head.h`.
- Detected declarations: `struct mpage_readpage_args`, `struct mpage_data`, `function Copyright`, `function mpage_write_end_io`, `function bio_for_each_folio_all`, `function map_buffer_to_folio`, `function buffer_mapped`, `function mpage_readahead`, `function mpage_read_folio`, `function clean_buffers`.
- Atlas domain: Core OS / VFS And Filesystem Core.
- Implementation status: integration implementation candidate.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.