Skip to contentSkip to conversation

ext4, f2fs: stop using PG_error for fscrypt and fsverity

PATCH Superseded Eric Biggers 1 participant 4 messages Jun 27, 2022 – Jul 19, 2022

Subsystems (5)

v1 of 5 Superseded Latest is v5 →

lore
Share & tools
lore

Eric Biggers

author maintainer
#0 lore raw

cover ext4, f2fs: stop using PG_error for fscrypt and fsverity

This series changes ext4 and f2fs to stop using PG_error to track decryption and verity errors. This is a step towards freeing up PG_error for other uses, as discussed at
https://lore.kernel.org/linux-fsdevel/[email protected]

Note: due to the interdependencies with fs/crypto/ and fs/verity/, I couldn't split this up into separate patches for each filesystem.

Eric Biggers (2):
fscrypt: stop using PG_error to track error status
fsverity: stop using PG_error to track error status

 fs/crypto/bio.c         | 16 +++++++----
 fs/ext4/readpage.c      | 16 +++++------
 fs/f2fs/compress.c      | 61 ++++++++++++++++++++---------------------
 fs/f2fs/data.c          | 60 +++++++++++++++++++++-------------------
 fs/verity/verify.c      | 12 ++++----
 include/linux/fscrypt.h |  5 ++--
 6 files changed, 88 insertions(+), 82 deletions(-)

base-commit: 0840a7914caa14315a3191178a9f72c742477860

Signature · 1 line
2.36.1
author maintainer
#1 lore raw

PATCH 1/2 fscrypt: stop using PG_error to track error status

From: Eric Biggers <[email protected]>

As a step towards freeing the PG_error flag for other uses, change ext4 and f2fs to stop using PG_error to track decryption errors. Instead, if a decryption error occurs, just mark the whole bio as failed. The coarser granularity isn't really a problem since it isn't any worse than what the block layer provides, and errors from a multi-page readahead aren't reported to applications unless a single-page read fails too.

---
 fs/crypto/bio.c         | 16 ++++++++++------
 fs/ext4/readpage.c      |  8 +++++---
 fs/f2fs/data.c          | 17 +++++++++--------
 include/linux/fscrypt.h |  5 +++--
 4 files changed, 27 insertions(+), 19 deletions(-)
fs/crypto/bio.c +10 -6
index 2217fe5ece6f9..1b4403136d05c 100644
@@ -25,21 +25,25 @@
  * then this function isn't applicable.  This function may sleep, so it must be
  * called from a workqueue rather than from the bio's bi_end_io callback.
  *
- * This function sets PG_error on any pages that contain any blocks that failed
- * to be decrypted.  The filesystem must not mark such pages uptodate.
+ * Return: %true on success; %false on failure.  On failure, bio->bi_status is
+ *	   also set to an error status.
  */
-void fscrypt_decrypt_bio(struct bio *bio)
+bool fscrypt_decrypt_bio(struct bio *bio)
 {
 	struct bio_vec *bv;
 	struct bvec_iter_all iter_all;
 
 	bio_for_each_segment_all(bv, bio, iter_all) {
 		struct page *page = bv->bv_page;
-		int ret = fscrypt_decrypt_pagecache_blocks(page, bv->bv_len,
+		int err = fscrypt_decrypt_pagecache_blocks(page, bv->bv_len,
 							   bv->bv_offset);
-		if (ret)
-			SetPageError(page);
+
+		if (err) {
+			bio->bi_status = errno_to_blk_status(err);
+			return false;
+		}
 	}
+	return true;
 }
 EXPORT_SYMBOL(fscrypt_decrypt_bio);
 
fs/ext4/readpage.c +5 -3
index e02a5f14e0211..5ce4706f68a7c 100644
@@ -96,10 +96,12 @@ static void decrypt_work(struct work_struct *work)
 {
 	struct bio_post_read_ctx *ctx =
 		container_of(work, struct bio_post_read_ctx, work);
+	struct bio *bio = ctx->bio;
 
-	fscrypt_decrypt_bio(ctx->bio);
-
-	bio_post_read_processing(ctx);
+	if (fscrypt_decrypt_bio(bio))
+		bio_post_read_processing(ctx);
+	else
+		__read_end_io(bio);
 }
 
 static void verity_work(struct work_struct *work)
fs/f2fs/data.c +9 -8
index 7fcbcf9797372..47065f17d579c 100644
@@ -138,7 +138,7 @@ static void f2fs_finish_read_bio(struct bio *bio)
 			continue;
 		}
 
-		/* PG_error was set if decryption or verity failed. */
+		/* PG_error was set if verity failed. */
 		if (bio->bi_status || PageError(page)) {
 			ClearPageUptodate(page);
 			/* will re-read again later */
@@ -184,7 +184,7 @@ static void f2fs_verify_bio(struct work_struct *work)
 			struct page *page = bv->bv_page;
 
 			if (!f2fs_is_compressed_page(page) &&
-			    !PageError(page) && !fsverity_verify_page(page))
+			    !fsverity_verify_page(page))
 				SetPageError(page);
 		}
 	} else {
@@ -234,10 +234,8 @@ static void f2fs_handle_step_decompress(struct bio_post_read_ctx *ctx)
 	bio_for_each_segment_all(bv, ctx->bio, iter_all) {
 		struct page *page = bv->bv_page;
 
-		/* PG_error was set if decryption failed. */
 		if (f2fs_is_compressed_page(page))
-			f2fs_end_read_compressed_page(page, PageError(page),
-						blkaddr);
+			f2fs_end_read_compressed_page(page, false, blkaddr);
 		else
 			all_compressed = false;
 
@@ -257,14 +255,17 @@ static void f2fs_post_read_work(struct work_struct *work)
 {
 	struct bio_post_read_ctx *ctx =
 		container_of(work, struct bio_post_read_ctx, work);
+	struct bio *bio = ctx->bio;
 
-	if (ctx->enabled_steps & STEP_DECRYPT)
-		fscrypt_decrypt_bio(ctx->bio);
+	if ((ctx->enabled_steps & STEP_DECRYPT) && !fscrypt_decrypt_bio(bio)) {
+		f2fs_finish_read_bio(bio);
+		return;
+	}
 
 	if (ctx->enabled_steps & STEP_DECOMPRESS)
 		f2fs_handle_step_decompress(ctx);
 
-	f2fs_verify_and_finish_bio(ctx->bio);
+	f2fs_verify_and_finish_bio(bio);
 }
 
 static void f2fs_read_end_io(struct bio *bio)
include/linux/fscrypt.h +3 -2
index e60d57c99cb6f..e9a3a51f29632 100644
@@ -348,7 +348,7 @@ u64 fscrypt_fname_siphash(const struct inode *dir, const struct qstr *name);
 int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags);
 
 /* bio.c */
-void fscrypt_decrypt_bio(struct bio *bio);
+bool fscrypt_decrypt_bio(struct bio *bio);
 int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
 			  sector_t pblk, unsigned int len);
 
@@ -641,8 +641,9 @@ static inline int fscrypt_d_revalidate(struct dentry *dentry,
 }
 
 /* bio.c */
-static inline void fscrypt_decrypt_bio(struct bio *bio)
+static inline bool fscrypt_decrypt_bio(struct bio *bio)
 {
+	return true;
 }
 
 static inline int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk,
Signature · 1 line
2.36.1
author maintainer
#2 lore raw

PATCH 2/2 fsverity: stop using PG_error to track error status

In reply to Eric Biggers

From: Eric Biggers <[email protected]>

As a step towards freeing the PG_error flag for other uses, change ext4 and f2fs to stop using PG_error to track verity errors. Instead, if a verity error occurs, just mark the whole bio as failed. The coarser granularity isn't really a problem since it isn't any worse than what the block layer provides, and errors from a multi-page readahead aren't reported to applications unless a single-page read fails too.

f2fs supports compression, which makes the f2fs changes a bit more complicated than desired, but the basic premise still works.

---
 fs/ext4/readpage.c |  8 ++----
 fs/f2fs/compress.c | 61 +++++++++++++++++++++++-----------------------
 fs/f2fs/data.c     | 49 ++++++++++++++++++++-----------------
 fs/verity/verify.c | 12 ++++-----
 4 files changed, 64 insertions(+), 66 deletions(-)
fs/ext4/readpage.c +2 -6
index 5ce4706f68a7c..e604ea4e102b7 100644
@@ -75,14 +75,10 @@ static void __read_end_io(struct bio *bio)
 	bio_for_each_segment_all(bv, bio, iter_all) {
 		page = bv->bv_page;
 
-		/* PG_error was set if any post_read step failed */
-		if (bio->bi_status || PageError(page)) {
+		if (bio->bi_status)
 			ClearPageUptodate(page);
-			/* will re-read again later */
-			ClearPageError(page);
-		} else {
+		else
 			SetPageUptodate(page);
-		}
 		unlock_page(page);
 	}
 	if (bio->bi_private)
fs/f2fs/compress.c +30 -31

96 lines not on this page · raw message

fs/f2fs/data.c +26 -23

129 lines not on this page · raw message

fs/verity/verify.c +6 -6
index 14e2fb49cff56..556dfbd4698de 100644
@@ -210,9 +210,8 @@ EXPORT_SYMBOL_GPL(fsverity_verify_page);
  * @bio: the bio to verify
  *
  * Verify a set of pages that have just been read from a verity file.  The pages
- * must be pagecache pages that are still locked and not yet uptodate.  Pages
- * that fail verification are set to the Error state.  Verification is skipped
- * for pages already in the Error state, e.g. due to fscrypt decryption failure.
+ * must be pagecache pages that are still locked and not yet uptodate.  If a
+ * page fails verification, then bio->bi_status is set to an error status.
  *
  * This is a helper function for use by the ->readahead() method of filesystems
  * that issue bios to read data directly into the page cache.  Filesystems that
@@ -254,9 +253,10 @@ void fsverity_verify_bio(struct bio *bio)
 		unsigned long level0_ra_pages =
 			min(max_ra_pages, params->level0_blocks - level0_index);
 
-		if (!PageError(page) &&
-		    !verify_page(inode, vi, req, page, level0_ra_pages))
-			SetPageError(page);
+		if (!verify_page(inode, vi, req, page, level0_ra_pages)) {
+			bio->bi_status = BLK_STS_IOERR;
+			break;
+		}
 	}
 
 	fsverity_free_hash_request(params->hash_alg, req);
Signature · 1 line
2.36.1
author maintainer
#3 lore raw
In reply to Eric Biggers
Quoted 21 lines · Eric Biggers

This series changes ext4 and f2fs to stop using PG_error to track decryption and verity errors. This is a step towards freeing up PG_error for other uses, as discussed at
https://lore.kernel.org/linux-fsdevel/[email protected]

Note: due to the interdependencies with fs/crypto/ and fs/verity/, I couldn't split this up into separate patches for each filesystem.

Eric Biggers (2):
fscrypt: stop using PG_error to track error status
fsverity: stop using PG_error to track error status

 fs/crypto/bio.c         | 16 +++++++----
 fs/ext4/readpage.c      | 16 +++++------
 fs/f2fs/compress.c      | 61 ++++++++++++++++++++---------------------
 fs/f2fs/data.c          | 60 +++++++++++++++++++++-------------------
 fs/verity/verify.c      | 12 ++++----
 include/linux/fscrypt.h |  5 ++--
 6 files changed, 88 insertions(+), 82 deletions(-)
Quoted 1 line

base-commit: 0840a7914caa14315a3191178a9f72c742477860

Any thoughts on this patchset from anyone?

- Eric