fs/buffer.c

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

File Facts

System
Linux kernel
Corpus path
fs/buffer.c
Extension
.c
Size
82662 bytes
Lines
3096
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.

Dependency Surface

Detected Declarations

Annotated Snippet

struct postprocess_bh_ctx {
	struct work_struct work;
	struct buffer_head *bh;
	struct fsverity_info *vi;
};

static void verify_bh(struct work_struct *work)
{
	struct postprocess_bh_ctx *ctx =
		container_of(work, struct postprocess_bh_ctx, work);
	struct buffer_head *bh = ctx->bh;
	bool valid;

	valid = fsverity_verify_blocks(ctx->vi, bh->b_folio, bh->b_size,
				       bh_offset(bh));
	end_buffer_async_read(bh, valid);
	kfree(ctx);
}

static void decrypt_bh(struct work_struct *work)
{
	struct postprocess_bh_ctx *ctx =
		container_of(work, struct postprocess_bh_ctx, work);
	struct buffer_head *bh = ctx->bh;
	int err;

	err = fscrypt_decrypt_pagecache_blocks(bh->b_folio, bh->b_size,
					       bh_offset(bh));
	if (err == 0 && ctx->vi) {
		/*
		 * We use different work queues for decryption and for verity
		 * because verity may require reading metadata pages that need
		 * decryption, and we shouldn't recurse to the same workqueue.
		 */
		INIT_WORK(&ctx->work, verify_bh);
		fsverity_enqueue_verify_work(&ctx->work);
		return;
	}
	end_buffer_async_read(bh, err == 0);
	kfree(ctx);
}

/*
 * I/O completion handler for block_read_full_folio() - folios
 * which come unlocked at the end of I/O.
 */
static void bh_end_async_read(struct bio *bio)
{
	struct buffer_head *bh;
	bool uptodate = bio_endio_bh(bio, &bh);
	struct inode *inode = bh->b_folio->mapping->host;
	bool decrypt = fscrypt_inode_uses_fs_layer_crypto(inode);
	struct fsverity_info *vi = NULL;

	/* needed by ext4 */
	if (bh->b_folio->index < DIV_ROUND_UP(inode->i_size, PAGE_SIZE))
		vi = fsverity_get_info(inode);

	/* Decrypt (with fscrypt) and/or verify (with fsverity) if needed. */
	if (uptodate && (decrypt || vi)) {
		struct postprocess_bh_ctx *ctx = kmalloc_obj(*ctx, GFP_ATOMIC);

		if (ctx) {
			ctx->bh = bh;
			ctx->vi = vi;
			if (decrypt) {
				INIT_WORK(&ctx->work, decrypt_bh);
				fscrypt_enqueue_decrypt_work(&ctx->work);
			} else {
				INIT_WORK(&ctx->work, verify_bh);
				fsverity_enqueue_verify_work(&ctx->work);
			}
			return;
		}
		uptodate = false;
	}
	end_buffer_async_read(bh, uptodate);
}

/**
 * bh_end_async_write - I/O end handler for async folio writes
 * @bio: The bio being completed.
 *
 * Pass this function to bh_submit() if you're doing the equivalent of
 * block_write_full_folio().  That is, the folio is unlocked, and will
 * have its writeback flag cleared once all async write buffers have
 * completed.
 */
void bh_end_async_write(struct bio *bio)
{

Annotation

Implementation Notes