diff options
Diffstat (limited to 'fs/buffer.c')
| -rw-r--r-- | fs/buffer.c | 124 | 
1 files changed, 86 insertions, 38 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index d9c6d1fbb6dd..9e1e2add541e 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -48,6 +48,7 @@  #include <linux/sched/mm.h>  #include <trace/events/block.h>  #include <linux/fscrypt.h> +#include <linux/fsverity.h>  #include "internal.h" @@ -60,7 +61,7 @@ static void submit_bh_wbc(blk_opf_t opf, struct buffer_head *bh,  inline void touch_buffer(struct buffer_head *bh)  {  	trace_block_touch_buffer(bh); -	mark_page_accessed(bh->b_page); +	folio_mark_accessed(bh->b_folio);  }  EXPORT_SYMBOL(touch_buffer); @@ -246,18 +247,18 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)  	unsigned long flags;  	struct buffer_head *first;  	struct buffer_head *tmp; -	struct page *page; -	int page_uptodate = 1; +	struct folio *folio; +	int folio_uptodate = 1;  	BUG_ON(!buffer_async_read(bh)); -	page = bh->b_page; +	folio = bh->b_folio;  	if (uptodate) {  		set_buffer_uptodate(bh);  	} else {  		clear_buffer_uptodate(bh);  		buffer_io_error(bh, ", async page read"); -		SetPageError(page); +		folio_set_error(folio);  	}  	/* @@ -265,14 +266,14 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)  	 * two buffer heads end IO at almost the same time and both  	 * decide that the page is now completely done.  	 */ -	first = page_buffers(page); +	first = folio_buffers(folio);  	spin_lock_irqsave(&first->b_uptodate_lock, flags);  	clear_buffer_async_read(bh);  	unlock_buffer(bh);  	tmp = bh;  	do {  		if (!buffer_uptodate(tmp)) -			page_uptodate = 0; +			folio_uptodate = 0;  		if (buffer_async_read(tmp)) {  			BUG_ON(!buffer_locked(tmp));  			goto still_busy; @@ -285,9 +286,9 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate)  	 * If all of the buffers are uptodate then we can set the page  	 * uptodate.  	 */ -	if (page_uptodate) -		SetPageUptodate(page); -	unlock_page(page); +	if (folio_uptodate) +		folio_mark_uptodate(folio); +	folio_unlock(folio);  	return;  still_busy: @@ -295,20 +296,53 @@ still_busy:  	return;  } -struct decrypt_bh_ctx { +struct postprocess_bh_ctx {  	struct work_struct work;  	struct buffer_head *bh;  }; +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(page_folio(bh->b_page), bh->b_size, +				       bh_offset(bh)); +	end_buffer_async_read(bh, valid); +	kfree(ctx); +} + +static bool need_fsverity(struct buffer_head *bh) +{ +	struct page *page = bh->b_page; +	struct inode *inode = page->mapping->host; + +	return fsverity_active(inode) && +		/* needed by ext4 */ +		page->index < DIV_ROUND_UP(inode->i_size, PAGE_SIZE); +} +  static void decrypt_bh(struct work_struct *work)  { -	struct decrypt_bh_ctx *ctx = -		container_of(work, struct decrypt_bh_ctx, 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_page, bh->b_size, -					       bh_offset(bh)); +	err = fscrypt_decrypt_pagecache_blocks(page_folio(bh->b_page), +					       bh->b_size, bh_offset(bh)); +	if (err == 0 && need_fsverity(bh)) { +		/* +		 * 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);  } @@ -319,15 +353,24 @@ static void decrypt_bh(struct work_struct *work)   */  static void end_buffer_async_read_io(struct buffer_head *bh, int uptodate)  { -	/* Decrypt if needed */ -	if (uptodate && -	    fscrypt_inode_uses_fs_layer_crypto(bh->b_page->mapping->host)) { -		struct decrypt_bh_ctx *ctx = kmalloc(sizeof(*ctx), GFP_ATOMIC); +	struct inode *inode = bh->b_folio->mapping->host; +	bool decrypt = fscrypt_inode_uses_fs_layer_crypto(inode); +	bool verify = need_fsverity(bh); + +	/* Decrypt (with fscrypt) and/or verify (with fsverity) if needed. */ +	if (uptodate && (decrypt || verify)) { +		struct postprocess_bh_ctx *ctx = +			kmalloc(sizeof(*ctx), GFP_ATOMIC);  		if (ctx) { -			INIT_WORK(&ctx->work, decrypt_bh);  			ctx->bh = bh; -			fscrypt_enqueue_decrypt_work(&ctx->work); +			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 = 0; @@ -344,21 +387,21 @@ void end_buffer_async_write(struct buffer_head *bh, int uptodate)  	unsigned long flags;  	struct buffer_head *first;  	struct buffer_head *tmp; -	struct page *page; +	struct folio *folio;  	BUG_ON(!buffer_async_write(bh)); -	page = bh->b_page; +	folio = bh->b_folio;  	if (uptodate) {  		set_buffer_uptodate(bh);  	} else {  		buffer_io_error(bh, ", lost async page write");  		mark_buffer_write_io_error(bh);  		clear_buffer_uptodate(bh); -		SetPageError(page); +		folio_set_error(folio);  	} -	first = page_buffers(page); +	first = folio_buffers(folio);  	spin_lock_irqsave(&first->b_uptodate_lock, flags);  	clear_buffer_async_write(bh); @@ -372,7 +415,7 @@ void end_buffer_async_write(struct buffer_head *bh, int uptodate)  		tmp = tmp->b_this_page;  	}  	spin_unlock_irqrestore(&first->b_uptodate_lock, flags); -	end_page_writeback(page); +	folio_end_writeback(folio);  	return;  still_busy: @@ -570,7 +613,7 @@ void write_boundary_block(struct block_device *bdev,  void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode)  {  	struct address_space *mapping = inode->i_mapping; -	struct address_space *buffer_mapping = bh->b_page->mapping; +	struct address_space *buffer_mapping = bh->b_folio->mapping;  	mark_buffer_dirty(bh);  	if (!mapping->private_data) { @@ -1073,7 +1116,7 @@ __getblk_slow(struct block_device *bdev, sector_t block,   * and then attach the address_space's inode to its superblock's dirty   * inode list.   * - * mark_buffer_dirty() is atomic.  It takes bh->b_page->mapping->private_lock, + * mark_buffer_dirty() is atomic.  It takes bh->b_folio->mapping->private_lock,   * i_pages lock and mapping->host->i_lock.   */  void mark_buffer_dirty(struct buffer_head *bh) @@ -1095,16 +1138,16 @@ void mark_buffer_dirty(struct buffer_head *bh)  	}  	if (!test_set_buffer_dirty(bh)) { -		struct page *page = bh->b_page; +		struct folio *folio = bh->b_folio;  		struct address_space *mapping = NULL; -		lock_page_memcg(page); -		if (!TestSetPageDirty(page)) { -			mapping = page_mapping(page); +		folio_memcg_lock(folio); +		if (!folio_test_set_dirty(folio)) { +			mapping = folio->mapping;  			if (mapping) -				__set_page_dirty(page, mapping, 0); +				__folio_mark_dirty(folio, mapping, 0);  		} -		unlock_page_memcg(page); +		folio_memcg_unlock(folio);  		if (mapping)  			__mark_inode_dirty(mapping->host, I_DIRTY_PAGES);  	} @@ -1117,8 +1160,8 @@ void mark_buffer_write_io_error(struct buffer_head *bh)  	set_buffer_write_io_error(bh);  	/* FIXME: do we need to set this in both places? */ -	if (bh->b_page && bh->b_page->mapping) -		mapping_set_error(bh->b_page->mapping, -EIO); +	if (bh->b_folio && bh->b_folio->mapping) +		mapping_set_error(bh->b_folio->mapping, -EIO);  	if (bh->b_assoc_map)  		mapping_set_error(bh->b_assoc_map, -EIO);  	rcu_read_lock(); @@ -1154,7 +1197,7 @@ void __bforget(struct buffer_head *bh)  {  	clear_buffer_dirty(bh);  	if (bh->b_assoc_map) { -		struct address_space *buffer_mapping = bh->b_page->mapping; +		struct address_space *buffer_mapping = bh->b_folio->mapping;  		spin_lock(&buffer_mapping->private_lock);  		list_del_init(&bh->b_assoc_buffers); @@ -2245,6 +2288,11 @@ int block_read_full_folio(struct folio *folio, get_block_t *get_block)  	int nr, i;  	int fully_mapped = 1;  	bool page_error = false; +	loff_t limit = i_size_read(inode); + +	/* This is needed for ext4. */ +	if (IS_ENABLED(CONFIG_FS_VERITY) && IS_VERITY(inode)) +		limit = inode->i_sb->s_maxbytes;  	VM_BUG_ON_FOLIO(folio_test_large(folio), folio); @@ -2253,7 +2301,7 @@ int block_read_full_folio(struct folio *folio, get_block_t *get_block)  	bbits = block_size_bits(blocksize);  	iblock = (sector_t)folio->index << (PAGE_SHIFT - bbits); -	lblock = (i_size_read(inode)+blocksize-1) >> bbits; +	lblock = (limit+blocksize-1) >> bbits;  	bh = head;  	nr = 0;  	i = 0;  |