fs/ext4/inode.c

Source file repositories/reference/linux-study-clean/fs/ext4/inode.c

File Facts

System
Linux kernel
Corpus path
fs/ext4/inode.c
Extension
.c
Size
202935 bytes
Lines
6879
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

struct mpage_da_data {
	/* These are input fields for ext4_do_writepages() */
	struct inode *inode;
	struct writeback_control *wbc;
	unsigned int can_map:1;	/* Can writepages call map blocks? */

	/* These are internal state of ext4_do_writepages() */
	loff_t start_pos;	/* The start pos to write */
	loff_t next_pos;	/* Current pos to examine */
	loff_t end_pos;		/* Last pos to examine */

	/*
	 * Extent to map - this can be after start_pos because that can be
	 * fully mapped. We somewhat abuse m_flags to store whether the extent
	 * is delalloc or unwritten.
	 */
	struct ext4_map_blocks map;
	struct ext4_io_submit io_submit;	/* IO submission data */
	unsigned int do_map:1;
	unsigned int scanned_until_end:1;
	unsigned int journalled_more_data:1;
};

static void mpage_release_unused_pages(struct mpage_da_data *mpd,
				       bool invalidate)
{
	unsigned nr, i;
	pgoff_t index, end;
	struct folio_batch fbatch;
	struct inode *inode = mpd->inode;
	struct address_space *mapping = inode->i_mapping;

	/* This is necessary when next_pos == 0. */
	if (mpd->start_pos >= mpd->next_pos)
		return;

	mpd->scanned_until_end = 0;
	if (invalidate) {
		ext4_lblk_t start, last;
		start = EXT4_B_TO_LBLK(inode, mpd->start_pos);
		last = mpd->next_pos >> inode->i_blkbits;

		/*
		 * avoid racing with extent status tree scans made by
		 * ext4_insert_delayed_block()
		 */
		down_write(&EXT4_I(inode)->i_data_sem);
		ext4_es_remove_extent(inode, start, last - start);
		up_write(&EXT4_I(inode)->i_data_sem);
	}

	folio_batch_init(&fbatch);
	index = mpd->start_pos >> PAGE_SHIFT;
	end = mpd->next_pos >> PAGE_SHIFT;
	while (index < end) {
		nr = filemap_get_folios(mapping, &index, end - 1, &fbatch);
		if (nr == 0)
			break;
		for (i = 0; i < nr; i++) {
			struct folio *folio = fbatch.folios[i];

			if (folio_pos(folio) < mpd->start_pos)
				continue;
			if (folio_next_index(folio) > end)
				continue;
			BUG_ON(!folio_test_locked(folio));
			BUG_ON(folio_test_writeback(folio));
			if (invalidate) {
				if (folio_mapped(folio)) {
					folio_clear_dirty_for_io(folio);
					/*
					 * Unmap folio from page
					 * tables to prevent
					 * subsequent accesses through
					 * stale PTEs. This ensures
					 * future accesses trigger new
					 * page faults rather than
					 * reusing the invalidated
					 * folio.
					 */
					unmap_mapping_pages(folio->mapping,
						folio->index,
						folio_nr_pages(folio), false);
				}
				block_invalidate_folio(folio, 0,
						folio_size(folio));
				folio_clear_uptodate(folio);
			}
			folio_unlock(folio);
		}

Annotation

Implementation Notes