fs/ext4/page-io.c

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

File Facts

System
Linux kernel
Corpus path
fs/ext4/page-io.c
Extension
.c
Size
17251 bytes
Lines
614
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

if (fscrypt_is_bounce_folio(folio)) {
			io_folio = folio;
			folio = fscrypt_pagecache_folio(folio);
		}

		if (bio->bi_status) {
			int err = blk_status_to_errno(bio->bi_status);
			mapping_set_error(folio->mapping, err);
		}
		bh = head = folio_buffers(folio);
		/*
		 * We check all buffers in the folio under b_uptodate_lock
		 * to avoid races with other end io clearing async_write flags
		 */
		spin_lock_irqsave(&head->b_uptodate_lock, flags);
		do {
			if (bh_offset(bh) < bio_start ||
			    bh_offset(bh) + bh->b_size > bio_end) {
				if (buffer_async_write(bh))
					under_io++;
				continue;
			}
			clear_buffer_async_write(bh);
			if (bio->bi_status) {
				set_buffer_write_io_error(bh);
				buffer_io_error(bh);
			}
		} while ((bh = bh->b_this_page) != head);
		spin_unlock_irqrestore(&head->b_uptodate_lock, flags);
		if (!under_io) {
			fscrypt_free_bounce_page(&io_folio->page);
			folio_end_writeback(folio);
		}
	}
}

static void ext4_release_io_end(ext4_io_end_t *io_end)
{
	struct bio *bio, *next_bio;

	BUG_ON(!list_empty(&io_end->list));
	BUG_ON(io_end->flag & EXT4_IO_END_UNWRITTEN);
	WARN_ON(io_end->handle);

	for (bio = io_end->bio; bio; bio = next_bio) {
		next_bio = bio->bi_private;
		ext4_finish_bio(bio);
		bio_put(bio);
	}
	ext4_free_io_end_vec(io_end);
	kmem_cache_free(io_end_cachep, io_end);
}

/*
 * On successful IO, check a range of space and convert unwritten extents to
 * written. On IO failure, check if journal abort is needed. Note that
 * we are protected from truncate touching same part of extent tree by the
 * fact that truncate code waits for all DIO to finish (thus exclusion from
 * direct IO is achieved) and also waits for writeback to complete. Thus we
 * cannot get to ext4_ext_truncate() before all IOs overlapping that range are
 * completed (happens from ext4_free_ioend()).
 */
static int ext4_end_io_end(ext4_io_end_t *io_end)
{
	struct inode *inode = io_end->inode;
	handle_t *handle = io_end->handle;
	struct super_block *sb = inode->i_sb;
	int ret = 0;

	ext4_debug("ext4_end_io_nolock: io_end 0x%p from inode %llu,list->next 0x%p,"
		   "list->prev 0x%p\n",
		   io_end, inode->i_ino, io_end->list.next, io_end->list.prev);

	/*
	 * Do not convert the unwritten extents if data writeback fails,
	 * or stale data may be exposed.
	 */
	io_end->handle = NULL;  /* Following call will use up the handle */
	if (unlikely(io_end->flag & EXT4_IO_END_FAILED)) {
		ret = -EIO;
		if (handle)
			jbd2_journal_free_reserved(handle);

		if (test_opt(sb, DATA_ERR_ABORT))
			jbd2_journal_abort(EXT4_SB(sb)->s_journal, ret);
	} else {
		ret = ext4_convert_unwritten_io_end_vec(handle, io_end);
	}
	if (ret < 0 && !ext4_emergency_state(sb) &&
	    io_end->flag & EXT4_IO_END_UNWRITTEN) {

Annotation

Implementation Notes