[f2fs-dev] [PATCH V2 00/13] Consolidate FS read I/O callbacks code
This patchset moves the "FS read I/O callbacks" code into a file of its own (i.e. fs/read_callbacks.c) and modifies the generic do_mpage_readpge() to make use of the functionality provided. "FS read I/O callbacks" code implements the state machine that needs to be executed after reading data from files that are encrypted and/or have verity metadata associated with them. With these changes in place, the patchset changes Ext4 to use mpage_readpage[s] instead of its own custom ext4_readpage[s]() functions. This is done to reduce duplicity of code across filesystems. Also, "FS read I/O callbacks" source files will be built only if one of CONFIG_FS_ENCRYPTION and CONFIG_FS_VERITY is enabled. The patchset also modifies fs/buffer.c and fscrypt functionality to get file encryption/decryption to work with subpage-sized blocks. The following fixes from Eric Biggers are prerequisites for this patchset, fscrypt: fix race where ->lookup() marks plaintext dentry as ciphertext fscrypt: only set dentry_operations on ciphertext dentries fscrypt: clear DCACHE_ENCRYPTED_NAME when unaliasing directory fscrypt: fix race allowing rename() and link() of ciphertext dentries fscrypt: clean up and improve dentry revalidation The patches can also be obtained from, "https://github.com/chandanr/linux.git subpage-encryption-v2" Changelog: V1 -> V2: 1. Removed the phrase "post_read_process" from file names and functions. Instead we now use the phrase "read_callbacks" in its place. 2. When performing changes associated with (1), the changes made by the patch "Remove the term 'bio' from post read processing" are made in the earlier patch "Consolidate 'read callbacks' into a new file". Hence the patch "Remove the term 'bio' from post read processing" is removed from the patchset. RFC V2 -> V1: 1. Test and verify FS_CFLG_OWN_PAGES subset of fscrypt_encrypt_page() code by executing fstests on UBIFS. 2. Implement F2fs function call back to check if the contents of a page holding a verity file's data needs to be verified. RFC V1 -> RFC V2: 1. Describe the purpose of "Post processing code" in the cover letter. 2. Fix build errors when CONFIG_FS_VERITY is enabled. Chandan Rajendra (13): ext4: Clear BH_Uptodate flag on decryption error Consolidate "read callbacks" into a new file fsverity: Add call back to decide if verity check has to be performed fsverity: Add call back to determine readpage limit fs/mpage.c: Integrate read callbacks ext4: Wire up ext4_readpage[s] to use mpage_readpage[s] Add decryption support for sub-pagesized blocks ext4: Decrypt all boundary blocks when doing buffered write ext4: Decrypt the block that needs to be partially zeroed fscrypt_encrypt_page: Loop across all blocks mapped by a page range ext4: Compute logical block and the page range to be encrypted fscrypt_zeroout_range: Encrypt all zeroed out blocks of a page ext4: Enable encryption for subpage-sized blocks Documentation/filesystems/fscrypt.rst | 4 +- fs/Kconfig| 4 + fs/Makefile | 4 + fs/buffer.c | 83 +++-- fs/crypto/Kconfig | 1 + fs/crypto/bio.c | 111 --- fs/crypto/crypto.c| 73 +++-- fs/crypto/fscrypt_private.h | 3 + fs/ext4/Makefile | 2 +- fs/ext4/ext4.h| 2 - fs/ext4/inode.c | 47 ++- fs/ext4/page-io.c | 9 +- fs/ext4/readpage.c| 445 -- fs/ext4/super.c | 39 ++- fs/f2fs/data.c| 148 ++--- fs/f2fs/super.c | 15 +- fs/mpage.c| 51 ++- fs/read_callbacks.c | 155 + fs/verity/Kconfig | 1 + fs/verity/verify.c| 12 + include/linux/buffer_head.h | 1 + include/linux/fscrypt.h | 20 +- include/linux/fsverity.h | 2 + include/linux/read_callbacks.h| 22 ++ 24 files changed, 522 insertions(+), 732 deletions(-) delete mode 100644 fs/ext4/readpage.c create mode 100644 fs/read_callbacks.c create mode 100644 include/linux/read_callbacks.h -- 2.19.1 ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH V2 05/13] fs/mpage.c: Integrate read callbacks
This commit adds code to make do_mpage_readpage() to be "read callbacks" aware i.e. for files requiring decryption/verification, do_mpage_readpage() now allocates a context structure and assigns the corresponding pointer to bio->bi_private. At endio time, a non-zero bio->bi_private indicates that after the read operation is performed, the bio's payload needs to be processed further before handing over the data to user space. The context structure is used for tracking the state machine associated with post read processing. Signed-off-by: Chandan Rajendra --- fs/mpage.c | 51 --- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/fs/mpage.c b/fs/mpage.c index 3f19da75178b..e342b859ee44 100644 --- a/fs/mpage.c +++ b/fs/mpage.c @@ -30,6 +30,10 @@ #include #include #include +#include +#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY) +#include +#endif #include "internal.h" /* @@ -50,6 +54,20 @@ static void mpage_end_io(struct bio *bio) int i; struct bvec_iter_all iter_all; +#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY) + if (!bio->bi_status && bio->bi_private) { + struct read_callbacks_ctx *ctx; + + ctx = bio->bi_private; + + read_callbacks(ctx); + return; + } + + if (bio->bi_private) + put_read_callbacks_ctx((struct read_callbacks_ctx *)(bio->bi_private)); +#endif + bio_for_each_segment_all(bv, bio, i, iter_all) { struct page *page = bv->bv_page; page_endio(page, bio_op(bio), @@ -189,7 +207,13 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args) block_in_file = (sector_t)page->index << (PAGE_SHIFT - blkbits); last_block = block_in_file + args->nr_pages * blocks_per_page; - last_block_in_file = (i_size_read(inode) + blocksize - 1) >> blkbits; +#ifdef CONFIG_FS_VERITY + if (IS_VERITY(inode) && inode->i_sb->s_vop->readpage_limit) + last_block_in_file = inode->i_sb->s_vop->readpage_limit(inode); + else +#endif + last_block_in_file = (i_size_read(inode) + blocksize - 1) + >> blkbits; if (last_block > last_block_in_file) last_block = last_block_in_file; page_block = 0; @@ -277,6 +301,14 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args) if (first_hole != blocks_per_page) { zero_user_segment(page, first_hole << blkbits, PAGE_SIZE); if (first_hole == 0) { +#ifdef CONFIG_FS_VERITY + if (IS_VERITY(inode)) { + if (!fsverity_check_hole(inode, page)) { + SetPageError(page); + goto confused; + } + } +#endif SetPageUptodate(page); unlock_page(page); goto out; @@ -299,7 +331,11 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args) alloc_new: if (args->bio == NULL) { - if (first_hole == blocks_per_page) { +#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY) + struct read_callbacks_ctx *ctx; +#endif + if (first_hole == blocks_per_page + && !(IS_ENCRYPTED(inode) || IS_VERITY(inode))) { if (!bdev_read_page(bdev, blocks[0] << (blkbits - 9), page)) goto out; @@ -310,6 +346,15 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args) gfp); if (args->bio == NULL) goto confused; + +#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY) + ctx = get_read_callbacks_ctx(inode, args->bio, page->index); + if (IS_ERR(ctx)) { + bio_put(args->bio); + args->bio = NULL; + goto confused; + } +#endif } length = first_hole << blkbits; @@ -331,7 +376,7 @@ static struct bio *do_mpage_readpage(struct mpage_readpage_args *args) confused: if (args->bio) args->bio = mpage_bio_submit(REQ_OP_READ, op_flags, args->bio); - if (!PageUptodate(page)) + if (!PageUptodate(page) && !PageError(page)) block_read_full_page(page, args->get_block); else unlock_page(page); -- 2.19.1 ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH V2 13/13] ext4: Enable encryption for subpage-sized blocks
Now that we have the code to support encryption for subpage-sized blocks, this commit removes the conditional check in filesystem mount code. The commit also changes the support statement in Documentation/filesystems/fscrypt.rst to reflect the fact that encryption of filesystems with blocksize less than page size now works. Signed-off-by: Chandan Rajendra --- Documentation/filesystems/fscrypt.rst | 4 ++-- fs/ext4/super.c | 7 --- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/Documentation/filesystems/fscrypt.rst b/Documentation/filesystems/fscrypt.rst index 08c23b60e016..ff2fea121da9 100644 --- a/Documentation/filesystems/fscrypt.rst +++ b/Documentation/filesystems/fscrypt.rst @@ -213,8 +213,8 @@ Contents encryption --- For file contents, each filesystem block is encrypted independently. -Currently, only the case where the filesystem block size is equal to -the system's page size (usually 4096 bytes) is supported. +Starting from Linux kernel 5.3, encryption of filesystems with block +size less than system's page size is supported. Each block's IV is set to the logical block number within the file as a little endian number, except that: diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 8e483afbaa2e..4acfefa98ec5 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -4432,13 +4432,6 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent) } } - if ((DUMMY_ENCRYPTION_ENABLED(sbi) || ext4_has_feature_encrypt(sb)) && - (blocksize != PAGE_SIZE)) { - ext4_msg(sb, KERN_ERR, -"Unsupported blocksize for fs encryption"); - goto failed_mount_wq; - } - if (DUMMY_ENCRYPTION_ENABLED(sbi) && !sb_rdonly(sb) && !ext4_has_feature_encrypt(sb)) { ext4_set_feature_encrypt(sb); -- 2.19.1 ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH V2 04/13] fsverity: Add call back to determine readpage limit
Ext4 and F2FS store verity metadata beyond i_size. This commit adds a call back pointer to "struct fsverity_operations" which helps in determining the the real file size limit upto which data can be read from the file. This call back will be required in order to get do_mpage_readpage() to read files having verity metadata appended beyond i_size. Signed-off-by: Chandan Rajendra --- fs/ext4/super.c | 17 + include/linux/fsverity.h | 1 + 2 files changed, 18 insertions(+) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 63d73b360f1d..8e483afbaa2e 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1428,6 +1428,22 @@ static struct page *ext4_read_verity_metadata_page(struct inode *inode, return read_mapping_page(inode->i_mapping, index, NULL); } +static loff_t ext4_readpage_limit(struct inode *inode) +{ + if (IS_VERITY(inode)) { + if (inode->i_verity_info) + /* limit to end of metadata region */ + return fsverity_full_i_size(inode); + /* +* fsverity_info is currently being set up and no user reads are +* allowed yet. It's easiest to just not enforce a limit yet. +*/ + return inode->i_sb->s_maxbytes; + } + + return i_size_read(inode); +} + static bool ext4_verity_required(struct inode *inode, pgoff_t index) { return index < (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT; @@ -1438,6 +1454,7 @@ static const struct fsverity_operations ext4_verityops = { .get_metadata_end = ext4_get_verity_metadata_end, .read_metadata_page = ext4_read_verity_metadata_page, .verity_required= ext4_verity_required, + .readpage_limit = ext4_readpage_limit, }; #endif /* CONFIG_FS_VERITY */ diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index b83712d6c79a..fc8113acbbfe 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -19,6 +19,7 @@ struct fsverity_operations { int (*get_metadata_end)(struct inode *inode, loff_t *metadata_end_ret); struct page *(*read_metadata_page)(struct inode *inode, pgoff_t index); bool (*verity_required)(struct inode *inode, pgoff_t index); + loff_t (*readpage_limit)(struct inode *inode); }; #ifdef CONFIG_FS_VERITY -- 2.19.1 ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH V2 02/13] Consolidate "read callbacks" into a new file
The "read callbacks" code is used by both Ext4 and F2FS. Hence to remove duplicity, this commit moves the code into include/linux/read_callbacks.h and fs/read_callbacks.c. The corresponding decrypt and verity "work" functions have been moved inside fscrypt and fsverity sources. With these in place, the read callbacks code now has to just invoke enqueue functions provided by fscrypt and fsverity. Signed-off-by: Chandan Rajendra --- fs/Kconfig | 4 + fs/Makefile| 4 + fs/crypto/Kconfig | 1 + fs/crypto/bio.c| 23 ++--- fs/crypto/crypto.c | 17 +-- fs/crypto/fscrypt_private.h| 3 + fs/ext4/ext4.h | 2 - fs/ext4/readpage.c | 183 + fs/ext4/super.c| 9 +- fs/f2fs/data.c | 148 -- fs/f2fs/super.c| 9 +- fs/read_callbacks.c| 136 fs/verity/Kconfig | 1 + fs/verity/verify.c | 12 +++ include/linux/fscrypt.h| 20 +--- include/linux/read_callbacks.h | 21 16 files changed, 251 insertions(+), 342 deletions(-) create mode 100644 fs/read_callbacks.c create mode 100644 include/linux/read_callbacks.h diff --git a/fs/Kconfig b/fs/Kconfig index 97f9eb8df713..03084f2dbeaf 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -308,6 +308,10 @@ config NFS_COMMON depends on NFSD || NFS_FS || LOCKD default y +config FS_READ_CALLBACKS + bool + default n + source "net/sunrpc/Kconfig" source "fs/ceph/Kconfig" source "fs/cifs/Kconfig" diff --git a/fs/Makefile b/fs/Makefile index 9dd2186e74b5..e0c0fce8cf40 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -21,6 +21,10 @@ else obj-y += no-block.o endif +ifeq ($(CONFIG_FS_READ_CALLBACKS),y) +obj-y += read_callbacks.o +endif + obj-$(CONFIG_PROC_FS) += proc_namespace.o obj-y += notify/ diff --git a/fs/crypto/Kconfig b/fs/crypto/Kconfig index f0de238000c0..163c328bcbd4 100644 --- a/fs/crypto/Kconfig +++ b/fs/crypto/Kconfig @@ -8,6 +8,7 @@ config FS_ENCRYPTION select CRYPTO_CTS select CRYPTO_SHA256 select KEYS + select FS_READ_CALLBACKS help Enable encryption of files and directories. This feature is similar to ecryptfs, but it is more memory diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index 5759bcd018cd..27f5618174f2 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -24,6 +24,8 @@ #include #include #include +#include + #include "fscrypt_private.h" static void __fscrypt_decrypt_bio(struct bio *bio, bool done) @@ -54,24 +56,15 @@ void fscrypt_decrypt_bio(struct bio *bio) } EXPORT_SYMBOL(fscrypt_decrypt_bio); -static void completion_pages(struct work_struct *work) +void fscrypt_decrypt_work(struct work_struct *work) { - struct fscrypt_ctx *ctx = - container_of(work, struct fscrypt_ctx, r.work); - struct bio *bio = ctx->r.bio; + struct read_callbacks_ctx *ctx = + container_of(work, struct read_callbacks_ctx, work); - __fscrypt_decrypt_bio(bio, true); - fscrypt_release_ctx(ctx); - bio_put(bio); -} + fscrypt_decrypt_bio(ctx->bio); -void fscrypt_enqueue_decrypt_bio(struct fscrypt_ctx *ctx, struct bio *bio) -{ - INIT_WORK(>r.work, completion_pages); - ctx->r.bio = bio; - fscrypt_enqueue_decrypt_work(>r.work); + read_callbacks(ctx); } -EXPORT_SYMBOL(fscrypt_enqueue_decrypt_bio); void fscrypt_pullback_bio_page(struct page **page, bool restore) { @@ -87,7 +80,7 @@ void fscrypt_pullback_bio_page(struct page **page, bool restore) ctx = (struct fscrypt_ctx *)page_private(bounce_page); /* restore control page */ - *page = ctx->w.control_page; + *page = ctx->control_page; if (restore) fscrypt_restore_control_page(bounce_page); diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 3fc84bf2b1e5..ffa9302a7351 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -53,6 +53,7 @@ struct kmem_cache *fscrypt_info_cachep; void fscrypt_enqueue_decrypt_work(struct work_struct *work) { + INIT_WORK(work, fscrypt_decrypt_work); queue_work(fscrypt_read_workqueue, work); } EXPORT_SYMBOL(fscrypt_enqueue_decrypt_work); @@ -70,11 +71,11 @@ void fscrypt_release_ctx(struct fscrypt_ctx *ctx) { unsigned long flags; - if (ctx->flags & FS_CTX_HAS_BOUNCE_BUFFER_FL && ctx->w.bounce_page) { - mempool_free(ctx->w.bounce_page, fscrypt_bounce_page_pool); - ctx->w.bounce_page = NULL; + if (ctx->flags & FS_CTX_HAS_BOUNCE_BUFFER_FL && ctx->bounce_page) { + mempool_free(ctx->bounce_page, fscrypt_bounce_page_pool); + ctx->bounce_page = NULL; } - ctx->w.control_page = NULL; + ctx->control_page =
[f2fs-dev] [PATCH V2 08/13] ext4: Decrypt all boundary blocks when doing buffered write
With subpage sized blocks, ext4_block_write_begin() can have up to two blocks to decrypt. Hence this commit invokes fscrypt_decrypt_page() for each of those blocks. Signed-off-by: Chandan Rajendra --- fs/ext4/inode.c | 33 +++-- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 1327e04334df..51744a3c3964 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1156,12 +1156,14 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, unsigned to = from + len; struct inode *inode = page->mapping->host; unsigned block_start, block_end; - sector_t block; + sector_t block, page_blk_nr; int err = 0; unsigned blocksize = inode->i_sb->s_blocksize; unsigned bbits; - struct buffer_head *bh, *head, *wait[2], **wait_bh = wait; + struct buffer_head *bh, *head, *wait[2]; + int nr_wait = 0; bool decrypt = false; + int i; BUG_ON(!PageLocked(page)); BUG_ON(from > PAGE_SIZE); @@ -1213,25 +1215,36 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, !buffer_unwritten(bh) && (block_start < from || block_end > to)) { ll_rw_block(REQ_OP_READ, 0, 1, ); - *wait_bh++ = bh; + wait[nr_wait++] = bh; decrypt = IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode); } } /* * If we issued read requests, let them complete. */ - while (wait_bh > wait) { - wait_on_buffer(*--wait_bh); - if (!buffer_uptodate(*wait_bh)) + for (i = 0; i < nr_wait; i++) { + wait_on_buffer(wait[i]); + if (!buffer_uptodate(wait[i])) err = -EIO; } if (unlikely(err)) { page_zero_new_buffers(page, from, to); } else if (decrypt) { - err = fscrypt_decrypt_page(page->mapping->host, page, - PAGE_SIZE, 0, page->index); - if (err) - clear_buffer_uptodate(*wait_bh); + page_blk_nr = (sector_t)page->index << (PAGE_SHIFT - bbits); + + for (i = 0; i < nr_wait; i++) { + int err2; + + block = page_blk_nr + (bh_offset(wait[i]) >> bbits); + err2 = fscrypt_decrypt_page(page->mapping->host, page, + wait[i]->b_size, + bh_offset(wait[i]), + block); + if (err2) { + clear_buffer_uptodate(wait[i]); + err = err2; + } + } } return err; -- 2.19.1 ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH V2 06/13] ext4: Wire up ext4_readpage[s] to use mpage_readpage[s]
Now that do_mpage_readpage() is "post read process" aware, this commit gets ext4_readpage[s] to use mpage_readpage[s] and deletes ext4's readpage.c since the associated functionality is not required anymore. Signed-off-by: Chandan Rajendra --- fs/ext4/Makefile | 2 +- fs/ext4/inode.c| 5 +- fs/ext4/readpage.c | 314 - 3 files changed, 3 insertions(+), 318 deletions(-) delete mode 100644 fs/ext4/readpage.c diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile index 8fdfcd3c3e04..7c38803a808d 100644 --- a/fs/ext4/Makefile +++ b/fs/ext4/Makefile @@ -8,7 +8,7 @@ obj-$(CONFIG_EXT4_FS) += ext4.o ext4-y := balloc.o bitmap.o block_validity.o dir.o ext4_jbd2.o extents.o \ extents_status.o file.o fsmap.o fsync.o hash.o ialloc.o \ indirect.o inline.o inode.o ioctl.o mballoc.o migrate.o \ - mmp.o move_extent.o namei.o page-io.o readpage.o resize.o \ + mmp.o move_extent.o namei.o page-io.o resize.o \ super.o symlink.o sysfs.o xattr.o xattr_trusted.o xattr_user.o ext4-$(CONFIG_EXT4_FS_POSIX_ACL) += acl.o diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 05b258db8673..1327e04334df 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3353,8 +3353,7 @@ static int ext4_readpage(struct file *file, struct page *page) ret = ext4_readpage_inline(inode, page); if (ret == -EAGAIN) - return ext4_mpage_readpages(page->mapping, NULL, page, 1, - false); + return mpage_readpage(page, ext4_get_block); return ret; } @@ -3369,7 +3368,7 @@ ext4_readpages(struct file *file, struct address_space *mapping, if (ext4_has_inline_data(inode)) return 0; - return ext4_mpage_readpages(mapping, pages, NULL, nr_pages, true); + return mpage_readpages(mapping, pages, nr_pages, ext4_get_block); } static void ext4_invalidatepage(struct page *page, unsigned int offset, diff --git a/fs/ext4/readpage.c b/fs/ext4/readpage.c deleted file mode 100644 index e363dededc21.. --- a/fs/ext4/readpage.c +++ /dev/null @@ -1,314 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * linux/fs/ext4/readpage.c - * - * Copyright (C) 2002, Linus Torvalds. - * Copyright (C) 2015, Google, Inc. - * - * This was originally taken from fs/mpage.c - * - * The intent is the ext4_mpage_readpages() function here is intended - * to replace mpage_readpages() in the general case, not just for - * encrypted files. It has some limitations (see below), where it - * will fall back to read_block_full_page(), but these limitations - * should only be hit when page_size != block_size. - * - * This will allow us to attach a callback function to support ext4 - * encryption. - * - * If anything unusual happens, such as: - * - * - encountering a page which has buffers - * - encountering a page which has a non-hole after a hole - * - encountering a page with non-contiguous blocks - * - * then this code just gives up and calls the buffer_head-based read function. - * It does handle a page which has holes at the end - that is a common case: - * the end-of-file on blocksize < PAGE_SIZE setups. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ext4.h" - -static inline bool ext4_bio_encrypted(struct bio *bio) -{ -#ifdef CONFIG_FS_ENCRYPTION - return unlikely(bio->bi_private != NULL); -#else - return false; -#endif -} - -/* - * I/O completion handler for multipage BIOs. - * - * The mpage code never puts partial pages into a BIO (except for end-of-file). - * If a page does not map to a contiguous run of blocks then it simply falls - * back to block_read_full_page(). - * - * Why is this? If a page's completion depends on a number of different BIOs - * which can complete in any order (or at the same time) then determining the - * status of that page is hard. See end_buffer_async_read() for the details. - * There is no point in duplicating all that complexity. - */ -static void mpage_end_io(struct bio *bio) -{ - struct bio_vec *bv; - int i; - struct bvec_iter_all iter_all; -#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY) - if (read_callbacks_required(bio)) { - struct read_callbacks_ctx *ctx = bio->bi_private; - - read_callbacks(ctx); - return; - } -#endif - bio_for_each_segment_all(bv, bio, i, iter_all) { - struct page *page = bv->bv_page; - - if (!bio->bi_status) { - SetPageUptodate(page); - } else { - ClearPageUptodate(page); - SetPageError(page); - } - unlock_page(page); - } - - bio_put(bio);
[f2fs-dev] [PATCH V2 01/13] ext4: Clear BH_Uptodate flag on decryption error
On an error return from fscrypt_decrypt_page(), ext4_block_write_begin() can return with the page's buffer_head marked with BH_Uptodate flag. This commit clears the BH_Uptodate flag in such cases. Signed-off-by: Chandan Rajendra --- fs/ext4/inode.c | 8 ++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 3c2e7f5a6c84..05b258db8673 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -1225,11 +1225,15 @@ static int ext4_block_write_begin(struct page *page, loff_t pos, unsigned len, if (!buffer_uptodate(*wait_bh)) err = -EIO; } - if (unlikely(err)) + if (unlikely(err)) { page_zero_new_buffers(page, from, to); - else if (decrypt) + } else if (decrypt) { err = fscrypt_decrypt_page(page->mapping->host, page, PAGE_SIZE, 0, page->index); + if (err) + clear_buffer_uptodate(*wait_bh); + } + return err; } #endif -- 2.19.1 ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH V2 12/13] fscrypt_zeroout_range: Encrypt all zeroed out blocks of a page
For subpage-sized blocks, this commit adds code to encrypt all zeroed out blocks mapped by a page. Signed-off-by: Chandan Rajendra --- fs/crypto/bio.c | 40 ++-- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/fs/crypto/bio.c b/fs/crypto/bio.c index 856f4694902d..46dd2ec50c7d 100644 --- a/fs/crypto/bio.c +++ b/fs/crypto/bio.c @@ -108,29 +108,23 @@ EXPORT_SYMBOL(fscrypt_pullback_bio_page); int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, sector_t pblk, unsigned int len) { - struct fscrypt_ctx *ctx; struct page *ciphertext_page = NULL; struct bio *bio; + u64 total_bytes, page_bytes; int ret, err = 0; - BUG_ON(inode->i_sb->s_blocksize != PAGE_SIZE); - - ctx = fscrypt_get_ctx(inode, GFP_NOFS); - if (IS_ERR(ctx)) - return PTR_ERR(ctx); + total_bytes = len << inode->i_blkbits; - ciphertext_page = fscrypt_alloc_bounce_page(ctx, GFP_NOWAIT); - if (IS_ERR(ciphertext_page)) { - err = PTR_ERR(ciphertext_page); - goto errout; - } + while (total_bytes) { + page_bytes = min_t(u64, total_bytes, PAGE_SIZE); - while (len--) { - err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk, -ZERO_PAGE(0), ciphertext_page, -PAGE_SIZE, 0, GFP_NOFS); - if (err) + ciphertext_page = fscrypt_encrypt_page(inode, ZERO_PAGE(0), + page_bytes, 0, lblk, GFP_NOFS); + if (IS_ERR(ciphertext_page)) { + err = PTR_ERR(ciphertext_page); + ciphertext_page = NULL; goto errout; + } bio = bio_alloc(GFP_NOWAIT, 1); if (!bio) { @@ -141,9 +135,8 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, bio->bi_iter.bi_sector = pblk << (inode->i_sb->s_blocksize_bits - 9); bio_set_op_attrs(bio, REQ_OP_WRITE, 0); - ret = bio_add_page(bio, ciphertext_page, - inode->i_sb->s_blocksize, 0); - if (ret != inode->i_sb->s_blocksize) { + ret = bio_add_page(bio, ciphertext_page, page_bytes, 0); + if (ret != page_bytes) { /* should never happen! */ WARN_ON(1); bio_put(bio); @@ -156,12 +149,15 @@ int fscrypt_zeroout_range(const struct inode *inode, pgoff_t lblk, bio_put(bio); if (err) goto errout; - lblk++; - pblk++; + + lblk += page_bytes >> inode->i_blkbits; + pblk += page_bytes >> inode->i_blkbits; + total_bytes -= page_bytes; } err = 0; errout: - fscrypt_release_ctx(ctx); + if (!IS_ERR_OR_NULL(ciphertext_page)) + fscrypt_restore_control_page(ciphertext_page); return err; } EXPORT_SYMBOL(fscrypt_zeroout_range); -- 2.19.1 ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH V2 11/13] ext4: Compute logical block and the page range to be encrypted
For subpage-sized blocks, the initial logical block number mapped by a page can be different from page->index. Hence this commit adds code to compute the first logical block mapped by the page and also the page range to be encrypted. Signed-off-by: Chandan Rajendra --- fs/ext4/page-io.c | 9 +++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c index 3e9298e6a705..75485ee9e800 100644 --- a/fs/ext4/page-io.c +++ b/fs/ext4/page-io.c @@ -418,6 +418,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io, { struct page *data_page = NULL; struct inode *inode = page->mapping->host; + u64 page_blk; unsigned block_start; struct buffer_head *bh, *head; int ret = 0; @@ -478,10 +479,14 @@ int ext4_bio_write_page(struct ext4_io_submit *io, if (IS_ENCRYPTED(inode) && S_ISREG(inode->i_mode) && nr_to_submit) { gfp_t gfp_flags = GFP_NOFS; + unsigned int page_bytes; + + page_bytes = round_up(len, i_blocksize(inode)); + page_blk = page->index << (PAGE_SHIFT - inode->i_blkbits); retry_encrypt: - data_page = fscrypt_encrypt_page(inode, page, PAGE_SIZE, 0, - page->index, gfp_flags); + data_page = fscrypt_encrypt_page(inode, page, page_bytes, 0, + page_blk, gfp_flags); if (IS_ERR(data_page)) { ret = PTR_ERR(data_page); if (ret == -ENOMEM && wbc->sync_mode == WB_SYNC_ALL) { -- 2.19.1 ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH V2 07/13] Add decryption support for sub-pagesized blocks
To support decryption of sub-pagesized blocks this commit adds code to, 1. Track buffer head in "struct read_callbacks_ctx". 2. Pass buffer head argument to all read callbacks. 3. In the corresponding endio, loop across all the blocks mapped by the page, decrypting each block in turn. Signed-off-by: Chandan Rajendra --- fs/buffer.c| 83 +- fs/crypto/bio.c| 50 +--- fs/crypto/crypto.c | 19 +++- fs/f2fs/data.c | 2 +- fs/mpage.c | 2 +- fs/read_callbacks.c| 53 ++ include/linux/buffer_head.h| 1 + include/linux/read_callbacks.h | 5 +- 8 files changed, 154 insertions(+), 61 deletions(-) diff --git a/fs/buffer.c b/fs/buffer.c index ce357602f471..f324727e24bb 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -45,6 +45,7 @@ #include #include #include +#include #include static int fsync_buffers_list(spinlock_t *lock, struct list_head *list); @@ -245,11 +246,7 @@ __find_get_block_slow(struct block_device *bdev, sector_t block) return ret; } -/* - * I/O completion handler for block_read_full_page() - pages - * which come unlocked at the end of I/O. - */ -static void end_buffer_async_read(struct buffer_head *bh, int uptodate) +void end_buffer_page_read(struct buffer_head *bh) { unsigned long flags; struct buffer_head *first; @@ -257,17 +254,7 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate) struct page *page; int page_uptodate = 1; - BUG_ON(!buffer_async_read(bh)); - page = bh->b_page; - if (uptodate) { - set_buffer_uptodate(bh); - } else { - clear_buffer_uptodate(bh); - buffer_io_error(bh, ", async page read"); - SetPageError(page); - } - /* * Be _very_ careful from here on. Bad things can happen if * two buffer heads end IO at almost the same time and both @@ -305,6 +292,44 @@ static void end_buffer_async_read(struct buffer_head *bh, int uptodate) local_irq_restore(flags); return; } +EXPORT_SYMBOL(end_buffer_page_read); + +/* + * I/O completion handler for block_read_full_page() - pages + * which come unlocked at the end of I/O. + */ +static void end_buffer_async_read(struct buffer_head *bh, int uptodate) +{ + struct page *page; + + BUG_ON(!buffer_async_read(bh)); + +#if defined(CONFIG_FS_ENCRYPTION) || defined(CONFIG_FS_VERITY) + if (uptodate && bh->b_private) { + struct read_callbacks_ctx *ctx = bh->b_private; + + read_callbacks(ctx); + return; + } + + if (bh->b_private) { + struct read_callbacks_ctx *ctx = bh->b_private; + + WARN_ON(uptodate); + put_read_callbacks_ctx(ctx); + } +#endif + page = bh->b_page; + if (uptodate) { + set_buffer_uptodate(bh); + } else { + clear_buffer_uptodate(bh); + buffer_io_error(bh, ", async page read"); + SetPageError(page); + } + + end_buffer_page_read(bh); +} /* * Completion handler for block_write_full_page() - pages which are unlocked @@ -2220,7 +2245,11 @@ int block_read_full_page(struct page *page, get_block_t *get_block) { struct inode *inode = page->mapping->host; sector_t iblock, lblock; - struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE]; + struct buffer_head *bh, *head; + struct { + sector_t blk_nr; + struct buffer_head *bh; + } arr[MAX_BUF_PER_PAGE]; unsigned int blocksize, bbits; int nr, i; int fully_mapped = 1; @@ -2262,7 +2291,9 @@ int block_read_full_page(struct page *page, get_block_t *get_block) if (buffer_uptodate(bh)) continue; } - arr[nr++] = bh; + arr[nr].blk_nr = iblock; + arr[nr].bh = bh; + ++nr; } while (i++, iblock++, (bh = bh->b_this_page) != head); if (fully_mapped) @@ -2281,7 +2312,7 @@ int block_read_full_page(struct page *page, get_block_t *get_block) /* Stage two: lock the buffers */ for (i = 0; i < nr; i++) { - bh = arr[i]; + bh = arr[i].bh; lock_buffer(bh); mark_buffer_async_read(bh); } @@ -2292,11 +2323,21 @@ int block_read_full_page(struct page *page, get_block_t *get_block) * the underlying blockdev brought it uptodate (the sct fix). */ for (i = 0; i < nr; i++) { - bh = arr[i]; - if (buffer_uptodate(bh)) + bh = arr[i].bh; + if (buffer_uptodate(bh)) { end_buffer_async_read(bh, 1); - else +
[f2fs-dev] [PATCH V2 03/13] fsverity: Add call back to decide if verity check has to be performed
Ext4 and F2FS store verity metadata in data extents (beyond inode->i_size) associated with a file. But other filesystems might choose alternative means to store verity metadata. Hence this commit adds a callback function pointer to 'struct fsverity_operations' to help in deciding if verity operation needs to performed against a page-cache page holding file data. Signed-off-by: Chandan Rajendra --- fs/ext4/super.c | 6 ++ fs/f2fs/super.c | 6 ++ fs/read_callbacks.c | 4 +++- include/linux/fsverity.h | 1 + 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/fs/ext4/super.c b/fs/ext4/super.c index aba724f82cc3..63d73b360f1d 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -1428,10 +1428,16 @@ static struct page *ext4_read_verity_metadata_page(struct inode *inode, return read_mapping_page(inode->i_mapping, index, NULL); } +static bool ext4_verity_required(struct inode *inode, pgoff_t index) +{ + return index < (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT; +} + static const struct fsverity_operations ext4_verityops = { .set_verity = ext4_set_verity, .get_metadata_end = ext4_get_verity_metadata_end, .read_metadata_page = ext4_read_verity_metadata_page, + .verity_required= ext4_verity_required, }; #endif /* CONFIG_FS_VERITY */ diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c index 2f75f06c784a..cd1299e1f92d 100644 --- a/fs/f2fs/super.c +++ b/fs/f2fs/super.c @@ -2257,10 +2257,16 @@ static struct page *f2fs_read_verity_metadata_page(struct inode *inode, return read_mapping_page(inode->i_mapping, index, NULL); } +static bool f2fs_verity_required(struct inode *inode, pgoff_t index) +{ + return index < (i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT; +} + static const struct fsverity_operations f2fs_verityops = { .set_verity = f2fs_set_verity, .get_metadata_end = f2fs_get_verity_metadata_end, .read_metadata_page = f2fs_read_verity_metadata_page, + .verity_required= f2fs_verity_required, }; #endif /* CONFIG_FS_VERITY */ diff --git a/fs/read_callbacks.c b/fs/read_callbacks.c index b6d5b95e67d7..6dea54b0baa9 100644 --- a/fs/read_callbacks.c +++ b/fs/read_callbacks.c @@ -86,7 +86,9 @@ struct read_callbacks_ctx *get_read_callbacks_ctx(struct inode *inode, read_callbacks_steps |= 1 << STEP_DECRYPT; #ifdef CONFIG_FS_VERITY if (inode->i_verity_info != NULL && - (index < ((i_size_read(inode) + PAGE_SIZE - 1) >> PAGE_SHIFT))) + ((inode->i_sb->s_vop->verity_required + && inode->i_sb->s_vop->verity_required(inode, index)) + || (inode->i_sb->s_vop->verity_required == NULL))) read_callbacks_steps |= 1 << STEP_VERITY; #endif if (read_callbacks_steps) { diff --git a/include/linux/fsverity.h b/include/linux/fsverity.h index 7c33b42abf1b..b83712d6c79a 100644 --- a/include/linux/fsverity.h +++ b/include/linux/fsverity.h @@ -18,6 +18,7 @@ struct fsverity_operations { int (*set_verity)(struct inode *inode, loff_t data_i_size); int (*get_metadata_end)(struct inode *inode, loff_t *metadata_end_ret); struct page *(*read_metadata_page)(struct inode *inode, pgoff_t index); + bool (*verity_required)(struct inode *inode, pgoff_t index); }; #ifdef CONFIG_FS_VERITY -- 2.19.1 ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH V2 10/13] fscrypt_encrypt_page: Loop across all blocks mapped by a page range
For subpage-sized blocks, this commit now encrypts all blocks mapped by a page range. Signed-off-by: Chandan Rajendra --- fs/crypto/crypto.c | 37 + 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/fs/crypto/crypto.c b/fs/crypto/crypto.c index 4f0d832cae71..2d65b431563f 100644 --- a/fs/crypto/crypto.c +++ b/fs/crypto/crypto.c @@ -242,18 +242,26 @@ struct page *fscrypt_encrypt_page(const struct inode *inode, { struct fscrypt_ctx *ctx; struct page *ciphertext_page = page; + int i, page_nr_blks; int err; BUG_ON(len % FS_CRYPTO_BLOCK_SIZE != 0); + page_nr_blks = len >> inode->i_blkbits; + if (inode->i_sb->s_cop->flags & FS_CFLG_OWN_PAGES) { /* with inplace-encryption we just encrypt the page */ - err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk_num, page, -ciphertext_page, len, offs, -gfp_flags); - if (err) - return ERR_PTR(err); - + for (i = 0; i < page_nr_blks; i++) { + err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, + lblk_num, page, + ciphertext_page, + i_blocksize(inode), offs, + gfp_flags); + if (err) + return ERR_PTR(err); + ++lblk_num; + offs += i_blocksize(inode); + } return ciphertext_page; } @@ -269,12 +277,17 @@ struct page *fscrypt_encrypt_page(const struct inode *inode, goto errout; ctx->control_page = page; - err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk_num, -page, ciphertext_page, len, offs, -gfp_flags); - if (err) { - ciphertext_page = ERR_PTR(err); - goto errout; + + for (i = 0; i < page_nr_blks; i++) { + err = fscrypt_do_page_crypto(inode, FS_ENCRYPT, lblk_num, + page, ciphertext_page, + i_blocksize(inode), offs, gfp_flags); + if (err) { + ciphertext_page = ERR_PTR(err); + goto errout; + } + ++lblk_num; + offs += i_blocksize(inode); } SetPagePrivate(ciphertext_page); set_page_private(ciphertext_page, (unsigned long)ctx); -- 2.19.1 ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
[f2fs-dev] [PATCH V2 09/13] ext4: Decrypt the block that needs to be partially zeroed
__ext4_block_zero_page_range decrypts the entire page. This commit decrypts the block to be partially zeroed instead of the whole page. Signed-off-by: Chandan Rajendra --- fs/ext4/inode.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index 51744a3c3964..ade1816697a8 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -4080,9 +4080,10 @@ static int __ext4_block_zero_page_range(handle_t *handle, if (S_ISREG(inode->i_mode) && IS_ENCRYPTED(inode)) { /* We expect the key to be set. */ BUG_ON(!fscrypt_has_encryption_key(inode)); - BUG_ON(blocksize != PAGE_SIZE); WARN_ON_ONCE(fscrypt_decrypt_page(page->mapping->host, - page, PAGE_SIZE, 0, page->index)); + page, blocksize, + round_down(offset, blocksize), + iblock)); } } if (ext4_should_journal_data(inode)) { -- 2.19.1 ___ Linux-f2fs-devel mailing list Linux-f2fs-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
Re: [f2fs-dev] [PATCH] f2fs: Add option to limit required GC for checkpoint=disable
Hi Daniel, On 2019/4/24 9:25, Daniel Rosenberg wrote: > This extends the checkpoint option to allow checkpoint=disable:%u > This allows you to specify what percent of the drive you are willing > to lose access to while mounting with checkpoint=disable. If the amount > lost would be higher, the mount will return -EAGAIN. > Currently, we need to run garbage collection until the amount of holes > is smaller than the OVP space. With the new option, f2fs can mark > space as unusable up front instead of requiring that > the space be freed up with garbage collection. > > Signed-off-by: Daniel Rosenberg > --- > Documentation/ABI/testing/sysfs-fs-f2fs | 8 + > Documentation/filesystems/f2fs.txt | 8 +++-- > fs/f2fs/f2fs.h | 6 +++- > fs/f2fs/segment.c | 17 -- > fs/f2fs/super.c | 44 + > fs/f2fs/sysfs.c | 16 + > 6 files changed, 72 insertions(+), 27 deletions(-) > > diff --git a/Documentation/ABI/testing/sysfs-fs-f2fs > b/Documentation/ABI/testing/sysfs-fs-f2fs > index 91822ce258317..d65b9ebc56190 100644 > --- a/Documentation/ABI/testing/sysfs-fs-f2fs > +++ b/Documentation/ABI/testing/sysfs-fs-f2fs > @@ -243,3 +243,11 @@ Description: >- Del: echo '[h/c]!extension' > > /sys/fs/f2fs//extension_list >- [h] means add/del hot file extension >- [c] means add/del cold file extension > + > +What:/sys/fs/f2fs//unusable > +Date April 2019 > +Contact: "Daniel Rosenberg" > +Description: > + Displays the number of blocks that are unusable during > checkpoint=disable Maybe it will be more clear to indicate what you implement in unusable_show(): If checkpoint=enable, it displays... If checkpoint=disable, it displays... > + or the number of blocks that would be unusable if > checkpoint=disable > + were to be set. > diff --git a/Documentation/filesystems/f2fs.txt > b/Documentation/filesystems/f2fs.txt > index f7b5e4ff0de3e..b3b5534407da7 100644 > --- a/Documentation/filesystems/f2fs.txt > +++ b/Documentation/filesystems/f2fs.txt > @@ -214,11 +214,15 @@ fsync_mode=%s Control the policy of fsync. > Currently supports "posix", > non-atomic files likewise "nobarrier" mount option. > test_dummy_encryption Enable dummy encryption, which provides a fake fscrypt > context. The fake fscrypt context is used by xfstests. > -checkpoint=%s Set to "disable" to turn off checkpointing. Set to > "enable" > +checkpoint=%s[:%u] Set to "disable" to turn off checkpointing. Set to > "enable" > to reenable checkpointing. Is enabled by default. > While > disabled, any unmounting or unexpected shutdowns will > cause > the filesystem contents to appear as they did when the > - filesystem was mounted with that option. > + filesystem was mounted with that option. While > mounting > + with disabled, you may optionally add a percentage to > + limit the amount of space that checkpoint=disable > denies > + access to. If this is set, the mount may return > EAGAIN if > + additional garbage collection is required to meet the > limit > > > > DEBUGFS ENTRIES > diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h > index 30acde08822ef..d0477251cec56 100644 > --- a/fs/f2fs/f2fs.h > +++ b/fs/f2fs/f2fs.h > @@ -136,6 +136,9 @@ struct f2fs_mount_info { > int alloc_mode; /* segment allocation policy */ > int fsync_mode; /* fsync policy */ > bool test_dummy_encryption; /* test dummy encryption */ > + block_t unusable_percent_cap; /* Percent of space allowed to be > + * unusable when disabling checkpoint > + */ > }; > > #define F2FS_FEATURE_ENCRYPT 0x0001 > @@ -3049,7 +3052,8 @@ bool f2fs_issue_discard_timeout(struct f2fs_sb_info > *sbi); > void f2fs_clear_prefree_segments(struct f2fs_sb_info *sbi, > struct cp_control *cpc); > void f2fs_dirty_to_prefree(struct f2fs_sb_info *sbi); > -int f2fs_disable_cp_again(struct f2fs_sb_info *sbi); > +block_t f2fs_get_unusable_blocks(struct f2fs_sb_info *sbi); > +int f2fs_disable_cp_again(struct f2fs_sb_info *sbi, block_t unusable); > void f2fs_release_discard_addrs(struct f2fs_sb_info *sbi); > int f2fs_npages_for_summary_flush(struct f2fs_sb_info *sbi, bool for_ra); > void f2fs_allocate_new_segments(struct f2fs_sb_info *sbi); > diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c > index a3380d1de6000..704224f4a2866 100644 > ---