[f2fs-dev] f2fs: trying to write to read-only block-device

2019-04-14 Thread Ju Hyung Park
Hi,

While I was playing around a f2fs image dumped from an Android device,
I observed that f2fs were trying to write to the image when I mounted
it via ro.

The host is Linux 4.19 with 5.1-rc1-4.19 merged.

f2fs might be trying to write to the device when the quota is
corrupted, regardless of ro being passed to the mount option or not.

I believe this is an easy issue to fix.

Thanks.

[17431.491120] F2FS-fs (loop0): orphan cleanup on readonly fs
[17431.491121] F2FS-fs (loop0): quota file may be corrupted, skip loading it
[17431.491710] F2FS-fs (loop0): recover fsync data on readonly fs
[17431.491711] F2FS-fs (loop0): quota file may be corrupted, skip loading it
[17431.492021] [ cut here ]
[17431.492022] generic_make_request: Trying to write to read-only
block-device loop0 (partno 0)
[17431.492035] WARNING: CPU: 0 PID: 23437 at block/blk-core.c:2174
generic_make_request_checks+0x594/0x630
[17431.492081] CPU: 0 PID: 23437 Comm: mount Tainted: G U  W
  4.19.33-zen+ #1
[17431.492082] Hardware name: LG Electronics
14ZD980-GX50K/14Z980, BIOS K2ZC0250 X64 03/08/2018
[17431.492084] RIP: 0010:generic_make_request_checks+0x594/0x630
[17431.492085] Code: 5c 03 00 00 48 8d 74 24 08 48 89 df c6 05 71 ec
36 01 01 e8 6e 91 01 00 48 89 c6 44 89 ea 48 c7 c7 10 61 59 82 e8 21
bb a7 ff <0f> 0b 48 8b 7b 08 e9 ee fa ff ff 65 8b 05 8a 71 91 7e 89 c0
48 0f
[17431.492086] RSP: 0018:88825a94b700 EFLAGS: 00010286
[17431.492087] RAX: 0050 RBX: 88842d3e0b00 RCX: 0006
[17431.492088] RDX: 0007 RSI: 0082 RDI: 888433416340
[17431.492088] RBP: 8884303d1d10 R08: 0004 R09: 0542
[17431.492089] R10: 0001 R11: 027f R12: 1000
[17431.492090] R13:  R14: 88840a179000 R15: 88825a94b870
[17431.492091] FS:  7fd885c988c0() GS:88843340()
knlGS:
[17431.492091] CS:  0010 DS:  ES:  CR0: 80050033
[17431.492092] CR2: 7fd88636eee0 CR3: 00017a4c3006 CR4: 003606f0
[17431.492093] Call Trace:
[17431.492096]  ? generic_make_request+0x46/0x3d0
[17431.492098]  ? wait_woken+0x80/0x80
[17431.492099]  ? mempool_alloc+0xb7/0x1a0
[17431.492101]  ? submit_bio+0x30/0x110
[17431.492102]  ? bvec_alloc+0x7c/0xd0
[17431.492104]  ? __submit_merged_bio+0x68/0x390
[17431.492106]  ? f2fs_submit_page_write+0x1bb/0x7f0
[17431.492108]  ? f2fs_do_write_meta_page+0x7f/0x160
[17431.492109]  ? __f2fs_write_meta_page+0x70/0x140
[17431.492110]  ? f2fs_sync_meta_pages+0x140/0x250
[17431.492112]  ? f2fs_write_checkpoint+0x5c5/0x17b0
[17431.492115]  ? __schedule+0x1b9/0x6b0
[17431.492116]  ? f2fs_sync_fs+0x9c/0x110
[17431.492119]  ? sync_filesystem+0x66/0x80
[17431.492120]  ? f2fs_recover_fsync_data+0x790/0xa30
[17431.492122]  ? f2fs_fill_super+0xe4e/0x1980
[17431.492123]  ? pointer+0x149/0x320
[17431.492124]  ? pcpu_alloc_area+0xdd/0x120
[17431.492126]  ? snprintf+0x39/0x40
[17431.492127]  ? mount_bdev+0x518/0x610
[17431.492128]  ? mount_bdev+0x518/0x610
[17431.492129]  ? f2fs_commit_super+0x160/0x160
[17431.492130]  ? mount_fs+0x34/0x13f
[17431.492132]  ? vfs_kern_mount.part.11+0x4f/0x120
[17431.492133]  ? do_mount+0x2d1/0xe40
[17431.492135]  ? memdup_user+0x39/0x60
[17431.492137]  ? __x64_sys_mount+0xbf/0xe0
[17431.492139]  ? do_syscall_64+0x4a/0xf0
[17431.492140]  ? entry_SYSCALL_64_after_hwframe+0x44/0xa9
[17431.492141] ---[ end trace 74417a97d9cf58c5 ]---
[17431.492237] print_req_error: I/O error, dev loop0, sector 16872
[17431.492243] print_req_error: I/O error, dev loop0, sector 21032
[17431.492245] print_req_error: I/O error, dev loop0, sector 47728
[17431.492247] print_req_error: I/O error, dev loop0, sector 4096
[17431.492258] F2FS-fs (loop0): Mounted with checkpoint version = 26e7ba3f


___
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel


[f2fs-dev] [RFC PATCH V2 09/14] ext4: Decrypt all boundary blocks when doing buffered write

2019-04-14 Thread Chandan Rajendra
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] [RFC PATCH V2 12/14] ext4: Compute logical block and the page range to be encrypted

2019-04-14 Thread Chandan Rajendra
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] [RFC PATCH V2 13/14] fscrypt_zeroout_range: Encrypt all zeroed out blocks of a page

2019-04-14 Thread Chandan Rajendra
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 83de1e46f546..2c6ce4218fd4 100644
--- a/fs/crypto/bio.c
+++ b/fs/crypto/bio.c
@@ -106,29 +106,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) {
@@ -139,9 +133,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);
@@ -154,12 +147,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] [RFC PATCH V2 11/14] fscrypt_encrypt_page: Loop across all blocks mapped by a page range

2019-04-14 Thread Chandan Rajendra
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..84d11d8eb7e3 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] [RFC PATCH V2 10/14] ext4: Decrypt the block that needs to be partially zeroed

2019-04-14 Thread Chandan Rajendra
__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


[f2fs-dev] [RFC PATCH V2 03/14] fsverity: Add call back to decide if verity check has to be performed

2019-04-14 Thread Chandan Rajendra
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/post_read_process.c   | 4 +++-
 include/linux/fsverity.h | 1 +
 3 files changed, 10 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/post_read_process.c b/fs/post_read_process.c
index d203fc263091..b60be77c7217 100644
--- a/fs/post_read_process.c
+++ b/fs/post_read_process.c
@@ -86,7 +86,9 @@ struct bio_post_read_ctx *get_bio_post_read_ctx(struct inode 
*inode,
post_read_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)))
post_read_steps |= 1 << STEP_VERITY;
 #endif
if (post_read_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] [RFC PATCH V2 05/14] fs/mpage.c: Integrate post read processing

2019-04-14 Thread Chandan Rajendra
This commit adds code to make do_mpage_readpage() to be "post read
processing" 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..9c291d6ddab6 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 bio_post_read_ctx *ctx;
+
+   ctx = bio->bi_private;
+
+   bio_post_read_processing(ctx);
+   return;
+   }
+
+   if (bio->bi_private)
+   put_bio_post_read_ctx((struct bio_post_read_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 bio_post_read_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_bio_post_read_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] [RFC PATCH V2 08/14] Add decryption support for sub-pagesized blocks

2019-04-14 Thread Chandan Rajendra
To support decryption of sub-pagesized blocks this commit adds code to,
1. Track buffer head in "struct post_read_ctx".
2. Pass buffer head argument to all "post read" processing functions.
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   | 85 +++
 fs/crypto/bio.c   | 48 +++--
 fs/crypto/crypto.c| 19 ++-
 fs/f2fs/data.c|  2 +-
 fs/mpage.c|  2 +-
 fs/post_read_process.c| 53 ---
 include/linux/buffer_head.h   |  1 +
 include/linux/post_read_process.h |  5 +-
 8 files changed, 154 insertions(+), 61 deletions(-)

diff --git a/fs/buffer.c b/fs/buffer.c
index ce357602f471..09cf9b1828d2 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,46 @@ 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 post_read_ctx *ctx = bh->b_private;
+
+   post_read_processing(ctx);
+   return;
+   }
+
+   if (bh->b_private) {
+   struct post_read_ctx *ctx = bh->b_private;
+
+   WARN_ON(uptodate);
+   put_post_read_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);
+
+   return;
+}
 
 /*
  * Completion handler for block_write_full_page() - pages which are unlocked
@@ -2220,7 +2247,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 +2293,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 +2314,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 +2325,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);

[f2fs-dev] [RFC PATCH V2 04/14] fsverity: Add call back to determine readpage limit

2019-04-14 Thread Chandan Rajendra
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  | 18 ++
 include/linux/fsverity.h |  1 +
 2 files changed, 19 insertions(+)

diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 63d73b360f1d..cadf50f9503f 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -1428,6 +1428,23 @@ 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)
+{
+#ifdef CONFIG_FS_VERITY
+   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;
+   }
+#endif
+   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 +1455,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] [RFC PATCH V2 01/14] ext4: Clear BH_Uptodate flag on decryption error

2019-04-14 Thread Chandan Rajendra
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