162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * fs/ext4/verity.c: fs-verity support for ext4 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2019 Google LLC 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci * Implementation of fsverity_operations for ext4. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * ext4 stores the verity metadata (Merkle tree and fsverity_descriptor) past 1262306a36Sopenharmony_ci * the end of the file, starting at the first 64K boundary beyond i_size. This 1362306a36Sopenharmony_ci * approach works because (a) verity files are readonly, and (b) pages fully 1462306a36Sopenharmony_ci * beyond i_size aren't visible to userspace but can be read/written internally 1562306a36Sopenharmony_ci * by ext4 with only some relatively small changes to ext4. This approach 1662306a36Sopenharmony_ci * avoids having to depend on the EA_INODE feature and on rearchitecturing 1762306a36Sopenharmony_ci * ext4's xattr support to support paging multi-gigabyte xattrs into memory, and 1862306a36Sopenharmony_ci * to support encrypting xattrs. Note that the verity metadata *must* be 1962306a36Sopenharmony_ci * encrypted when the file is, since it contains hashes of the plaintext data. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * Using a 64K boundary rather than a 4K one keeps things ready for 2262306a36Sopenharmony_ci * architectures with 64K pages, and it doesn't necessarily waste space on-disk 2362306a36Sopenharmony_ci * since there can be a hole between i_size and the start of the Merkle tree. 2462306a36Sopenharmony_ci */ 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include <linux/quotaops.h> 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci#include "ext4.h" 2962306a36Sopenharmony_ci#include "ext4_extents.h" 3062306a36Sopenharmony_ci#include "ext4_jbd2.h" 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic inline loff_t ext4_verity_metadata_pos(const struct inode *inode) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci return round_up(inode->i_size, 65536); 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* 3862306a36Sopenharmony_ci * Read some verity metadata from the inode. __vfs_read() can't be used because 3962306a36Sopenharmony_ci * we need to read beyond i_size. 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_cistatic int pagecache_read(struct inode *inode, void *buf, size_t count, 4262306a36Sopenharmony_ci loff_t pos) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci while (count) { 4562306a36Sopenharmony_ci struct folio *folio; 4662306a36Sopenharmony_ci size_t n; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci folio = read_mapping_folio(inode->i_mapping, pos >> PAGE_SHIFT, 4962306a36Sopenharmony_ci NULL); 5062306a36Sopenharmony_ci if (IS_ERR(folio)) 5162306a36Sopenharmony_ci return PTR_ERR(folio); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci n = memcpy_from_file_folio(buf, folio, pos, count); 5462306a36Sopenharmony_ci folio_put(folio); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci buf += n; 5762306a36Sopenharmony_ci pos += n; 5862306a36Sopenharmony_ci count -= n; 5962306a36Sopenharmony_ci } 6062306a36Sopenharmony_ci return 0; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci/* 6462306a36Sopenharmony_ci * Write some verity metadata to the inode for FS_IOC_ENABLE_VERITY. 6562306a36Sopenharmony_ci * kernel_write() can't be used because the file descriptor is readonly. 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_cistatic int pagecache_write(struct inode *inode, const void *buf, size_t count, 6862306a36Sopenharmony_ci loff_t pos) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci struct address_space *mapping = inode->i_mapping; 7162306a36Sopenharmony_ci const struct address_space_operations *aops = mapping->a_ops; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci if (pos + count > inode->i_sb->s_maxbytes) 7462306a36Sopenharmony_ci return -EFBIG; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci while (count) { 7762306a36Sopenharmony_ci size_t n = min_t(size_t, count, 7862306a36Sopenharmony_ci PAGE_SIZE - offset_in_page(pos)); 7962306a36Sopenharmony_ci struct page *page; 8062306a36Sopenharmony_ci void *fsdata = NULL; 8162306a36Sopenharmony_ci int res; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci res = aops->write_begin(NULL, mapping, pos, n, &page, &fsdata); 8462306a36Sopenharmony_ci if (res) 8562306a36Sopenharmony_ci return res; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci memcpy_to_page(page, offset_in_page(pos), buf, n); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci res = aops->write_end(NULL, mapping, pos, n, n, page, fsdata); 9062306a36Sopenharmony_ci if (res < 0) 9162306a36Sopenharmony_ci return res; 9262306a36Sopenharmony_ci if (res != n) 9362306a36Sopenharmony_ci return -EIO; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci buf += n; 9662306a36Sopenharmony_ci pos += n; 9762306a36Sopenharmony_ci count -= n; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci return 0; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic int ext4_begin_enable_verity(struct file *filp) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 10562306a36Sopenharmony_ci const int credits = 2; /* superblock and inode for ext4_orphan_add() */ 10662306a36Sopenharmony_ci handle_t *handle; 10762306a36Sopenharmony_ci int err; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (IS_DAX(inode) || ext4_test_inode_flag(inode, EXT4_INODE_DAX)) 11062306a36Sopenharmony_ci return -EINVAL; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (ext4_verity_in_progress(inode)) 11362306a36Sopenharmony_ci return -EBUSY; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci /* 11662306a36Sopenharmony_ci * Since the file was opened readonly, we have to initialize the jbd 11762306a36Sopenharmony_ci * inode and quotas here and not rely on ->open() doing it. This must 11862306a36Sopenharmony_ci * be done before evicting the inline data. 11962306a36Sopenharmony_ci */ 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci err = ext4_inode_attach_jinode(inode); 12262306a36Sopenharmony_ci if (err) 12362306a36Sopenharmony_ci return err; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci err = dquot_initialize(inode); 12662306a36Sopenharmony_ci if (err) 12762306a36Sopenharmony_ci return err; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci err = ext4_convert_inline_data(inode); 13062306a36Sopenharmony_ci if (err) 13162306a36Sopenharmony_ci return err; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) { 13462306a36Sopenharmony_ci ext4_warning_inode(inode, 13562306a36Sopenharmony_ci "verity is only allowed on extent-based files"); 13662306a36Sopenharmony_ci return -EOPNOTSUPP; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci /* 14062306a36Sopenharmony_ci * ext4 uses the last allocated block to find the verity descriptor, so 14162306a36Sopenharmony_ci * we must remove any other blocks past EOF which might confuse things. 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_ci err = ext4_truncate(inode); 14462306a36Sopenharmony_ci if (err) 14562306a36Sopenharmony_ci return err; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci handle = ext4_journal_start(inode, EXT4_HT_INODE, credits); 14862306a36Sopenharmony_ci if (IS_ERR(handle)) 14962306a36Sopenharmony_ci return PTR_ERR(handle); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci err = ext4_orphan_add(handle, inode); 15262306a36Sopenharmony_ci if (err == 0) 15362306a36Sopenharmony_ci ext4_set_inode_state(inode, EXT4_STATE_VERITY_IN_PROGRESS); 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci ext4_journal_stop(handle); 15662306a36Sopenharmony_ci return err; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/* 16062306a36Sopenharmony_ci * ext4 stores the verity descriptor beginning on the next filesystem block 16162306a36Sopenharmony_ci * boundary after the Merkle tree. Then, the descriptor size is stored in the 16262306a36Sopenharmony_ci * last 4 bytes of the last allocated filesystem block --- which is either the 16362306a36Sopenharmony_ci * block in which the descriptor ends, or the next block after that if there 16462306a36Sopenharmony_ci * weren't at least 4 bytes remaining. 16562306a36Sopenharmony_ci * 16662306a36Sopenharmony_ci * We can't simply store the descriptor in an xattr because it *must* be 16762306a36Sopenharmony_ci * encrypted when ext4 encryption is used, but ext4 encryption doesn't encrypt 16862306a36Sopenharmony_ci * xattrs. Also, if the descriptor includes a large signature blob it may be 16962306a36Sopenharmony_ci * too large to store in an xattr without the EA_INODE feature. 17062306a36Sopenharmony_ci */ 17162306a36Sopenharmony_cistatic int ext4_write_verity_descriptor(struct inode *inode, const void *desc, 17262306a36Sopenharmony_ci size_t desc_size, u64 merkle_tree_size) 17362306a36Sopenharmony_ci{ 17462306a36Sopenharmony_ci const u64 desc_pos = round_up(ext4_verity_metadata_pos(inode) + 17562306a36Sopenharmony_ci merkle_tree_size, i_blocksize(inode)); 17662306a36Sopenharmony_ci const u64 desc_end = desc_pos + desc_size; 17762306a36Sopenharmony_ci const __le32 desc_size_disk = cpu_to_le32(desc_size); 17862306a36Sopenharmony_ci const u64 desc_size_pos = round_up(desc_end + sizeof(desc_size_disk), 17962306a36Sopenharmony_ci i_blocksize(inode)) - 18062306a36Sopenharmony_ci sizeof(desc_size_disk); 18162306a36Sopenharmony_ci int err; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci err = pagecache_write(inode, desc, desc_size, desc_pos); 18462306a36Sopenharmony_ci if (err) 18562306a36Sopenharmony_ci return err; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci return pagecache_write(inode, &desc_size_disk, sizeof(desc_size_disk), 18862306a36Sopenharmony_ci desc_size_pos); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic int ext4_end_enable_verity(struct file *filp, const void *desc, 19262306a36Sopenharmony_ci size_t desc_size, u64 merkle_tree_size) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci struct inode *inode = file_inode(filp); 19562306a36Sopenharmony_ci const int credits = 2; /* superblock and inode for ext4_orphan_del() */ 19662306a36Sopenharmony_ci handle_t *handle; 19762306a36Sopenharmony_ci struct ext4_iloc iloc; 19862306a36Sopenharmony_ci int err = 0; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* 20162306a36Sopenharmony_ci * If an error already occurred (which fs/verity/ signals by passing 20262306a36Sopenharmony_ci * desc == NULL), then only clean-up is needed. 20362306a36Sopenharmony_ci */ 20462306a36Sopenharmony_ci if (desc == NULL) 20562306a36Sopenharmony_ci goto cleanup; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci /* Append the verity descriptor. */ 20862306a36Sopenharmony_ci err = ext4_write_verity_descriptor(inode, desc, desc_size, 20962306a36Sopenharmony_ci merkle_tree_size); 21062306a36Sopenharmony_ci if (err) 21162306a36Sopenharmony_ci goto cleanup; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* 21462306a36Sopenharmony_ci * Write all pages (both data and verity metadata). Note that this must 21562306a36Sopenharmony_ci * happen before clearing EXT4_STATE_VERITY_IN_PROGRESS; otherwise pages 21662306a36Sopenharmony_ci * beyond i_size won't be written properly. For crash consistency, this 21762306a36Sopenharmony_ci * also must happen before the verity inode flag gets persisted. 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_ci err = filemap_write_and_wait(inode->i_mapping); 22062306a36Sopenharmony_ci if (err) 22162306a36Sopenharmony_ci goto cleanup; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* 22462306a36Sopenharmony_ci * Finally, set the verity inode flag and remove the inode from the 22562306a36Sopenharmony_ci * orphan list (in a single transaction). 22662306a36Sopenharmony_ci */ 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci handle = ext4_journal_start(inode, EXT4_HT_INODE, credits); 22962306a36Sopenharmony_ci if (IS_ERR(handle)) { 23062306a36Sopenharmony_ci err = PTR_ERR(handle); 23162306a36Sopenharmony_ci goto cleanup; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci err = ext4_orphan_del(handle, inode); 23562306a36Sopenharmony_ci if (err) 23662306a36Sopenharmony_ci goto stop_and_cleanup; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci err = ext4_reserve_inode_write(handle, inode, &iloc); 23962306a36Sopenharmony_ci if (err) 24062306a36Sopenharmony_ci goto stop_and_cleanup; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci ext4_set_inode_flag(inode, EXT4_INODE_VERITY); 24362306a36Sopenharmony_ci ext4_set_inode_flags(inode, false); 24462306a36Sopenharmony_ci err = ext4_mark_iloc_dirty(handle, inode, &iloc); 24562306a36Sopenharmony_ci if (err) 24662306a36Sopenharmony_ci goto stop_and_cleanup; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci ext4_journal_stop(handle); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci ext4_clear_inode_state(inode, EXT4_STATE_VERITY_IN_PROGRESS); 25162306a36Sopenharmony_ci return 0; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistop_and_cleanup: 25462306a36Sopenharmony_ci ext4_journal_stop(handle); 25562306a36Sopenharmony_cicleanup: 25662306a36Sopenharmony_ci /* 25762306a36Sopenharmony_ci * Verity failed to be enabled, so clean up by truncating any verity 25862306a36Sopenharmony_ci * metadata that was written beyond i_size (both from cache and from 25962306a36Sopenharmony_ci * disk), removing the inode from the orphan list (if it wasn't done 26062306a36Sopenharmony_ci * already), and clearing EXT4_STATE_VERITY_IN_PROGRESS. 26162306a36Sopenharmony_ci */ 26262306a36Sopenharmony_ci truncate_inode_pages(inode->i_mapping, inode->i_size); 26362306a36Sopenharmony_ci ext4_truncate(inode); 26462306a36Sopenharmony_ci ext4_orphan_del(NULL, inode); 26562306a36Sopenharmony_ci ext4_clear_inode_state(inode, EXT4_STATE_VERITY_IN_PROGRESS); 26662306a36Sopenharmony_ci return err; 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic int ext4_get_verity_descriptor_location(struct inode *inode, 27062306a36Sopenharmony_ci size_t *desc_size_ret, 27162306a36Sopenharmony_ci u64 *desc_pos_ret) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct ext4_ext_path *path; 27462306a36Sopenharmony_ci struct ext4_extent *last_extent; 27562306a36Sopenharmony_ci u32 end_lblk; 27662306a36Sopenharmony_ci u64 desc_size_pos; 27762306a36Sopenharmony_ci __le32 desc_size_disk; 27862306a36Sopenharmony_ci u32 desc_size; 27962306a36Sopenharmony_ci u64 desc_pos; 28062306a36Sopenharmony_ci int err; 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci /* 28362306a36Sopenharmony_ci * Descriptor size is in last 4 bytes of last allocated block. 28462306a36Sopenharmony_ci * See ext4_write_verity_descriptor(). 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (!ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) { 28862306a36Sopenharmony_ci EXT4_ERROR_INODE(inode, "verity file doesn't use extents"); 28962306a36Sopenharmony_ci return -EFSCORRUPTED; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci path = ext4_find_extent(inode, EXT_MAX_BLOCKS - 1, NULL, 0); 29362306a36Sopenharmony_ci if (IS_ERR(path)) 29462306a36Sopenharmony_ci return PTR_ERR(path); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci last_extent = path[path->p_depth].p_ext; 29762306a36Sopenharmony_ci if (!last_extent) { 29862306a36Sopenharmony_ci EXT4_ERROR_INODE(inode, "verity file has no extents"); 29962306a36Sopenharmony_ci ext4_free_ext_path(path); 30062306a36Sopenharmony_ci return -EFSCORRUPTED; 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci end_lblk = le32_to_cpu(last_extent->ee_block) + 30462306a36Sopenharmony_ci ext4_ext_get_actual_len(last_extent); 30562306a36Sopenharmony_ci desc_size_pos = (u64)end_lblk << inode->i_blkbits; 30662306a36Sopenharmony_ci ext4_free_ext_path(path); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci if (desc_size_pos < sizeof(desc_size_disk)) 30962306a36Sopenharmony_ci goto bad; 31062306a36Sopenharmony_ci desc_size_pos -= sizeof(desc_size_disk); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci err = pagecache_read(inode, &desc_size_disk, sizeof(desc_size_disk), 31362306a36Sopenharmony_ci desc_size_pos); 31462306a36Sopenharmony_ci if (err) 31562306a36Sopenharmony_ci return err; 31662306a36Sopenharmony_ci desc_size = le32_to_cpu(desc_size_disk); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci /* 31962306a36Sopenharmony_ci * The descriptor is stored just before the desc_size_disk, but starting 32062306a36Sopenharmony_ci * on a filesystem block boundary. 32162306a36Sopenharmony_ci */ 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci if (desc_size > INT_MAX || desc_size > desc_size_pos) 32462306a36Sopenharmony_ci goto bad; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci desc_pos = round_down(desc_size_pos - desc_size, i_blocksize(inode)); 32762306a36Sopenharmony_ci if (desc_pos < ext4_verity_metadata_pos(inode)) 32862306a36Sopenharmony_ci goto bad; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci *desc_size_ret = desc_size; 33162306a36Sopenharmony_ci *desc_pos_ret = desc_pos; 33262306a36Sopenharmony_ci return 0; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cibad: 33562306a36Sopenharmony_ci EXT4_ERROR_INODE(inode, "verity file corrupted; can't find descriptor"); 33662306a36Sopenharmony_ci return -EFSCORRUPTED; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic int ext4_get_verity_descriptor(struct inode *inode, void *buf, 34062306a36Sopenharmony_ci size_t buf_size) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci size_t desc_size = 0; 34362306a36Sopenharmony_ci u64 desc_pos = 0; 34462306a36Sopenharmony_ci int err; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci err = ext4_get_verity_descriptor_location(inode, &desc_size, &desc_pos); 34762306a36Sopenharmony_ci if (err) 34862306a36Sopenharmony_ci return err; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (buf_size) { 35162306a36Sopenharmony_ci if (desc_size > buf_size) 35262306a36Sopenharmony_ci return -ERANGE; 35362306a36Sopenharmony_ci err = pagecache_read(inode, buf, desc_size, desc_pos); 35462306a36Sopenharmony_ci if (err) 35562306a36Sopenharmony_ci return err; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci return desc_size; 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_cistatic struct page *ext4_read_merkle_tree_page(struct inode *inode, 36162306a36Sopenharmony_ci pgoff_t index, 36262306a36Sopenharmony_ci unsigned long num_ra_pages) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci struct folio *folio; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci index += ext4_verity_metadata_pos(inode) >> PAGE_SHIFT; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci folio = __filemap_get_folio(inode->i_mapping, index, FGP_ACCESSED, 0); 36962306a36Sopenharmony_ci if (IS_ERR(folio) || !folio_test_uptodate(folio)) { 37062306a36Sopenharmony_ci DEFINE_READAHEAD(ractl, NULL, NULL, inode->i_mapping, index); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci if (!IS_ERR(folio)) 37362306a36Sopenharmony_ci folio_put(folio); 37462306a36Sopenharmony_ci else if (num_ra_pages > 1) 37562306a36Sopenharmony_ci page_cache_ra_unbounded(&ractl, num_ra_pages, 0); 37662306a36Sopenharmony_ci folio = read_mapping_folio(inode->i_mapping, index, NULL); 37762306a36Sopenharmony_ci if (IS_ERR(folio)) 37862306a36Sopenharmony_ci return ERR_CAST(folio); 37962306a36Sopenharmony_ci } 38062306a36Sopenharmony_ci return folio_file_page(folio, index); 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_cistatic int ext4_write_merkle_tree_block(struct inode *inode, const void *buf, 38462306a36Sopenharmony_ci u64 pos, unsigned int size) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci pos += ext4_verity_metadata_pos(inode); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci return pagecache_write(inode, buf, size, pos); 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ciconst struct fsverity_operations ext4_verityops = { 39262306a36Sopenharmony_ci .begin_enable_verity = ext4_begin_enable_verity, 39362306a36Sopenharmony_ci .end_enable_verity = ext4_end_enable_verity, 39462306a36Sopenharmony_ci .get_verity_descriptor = ext4_get_verity_descriptor, 39562306a36Sopenharmony_ci .read_merkle_tree_page = ext4_read_merkle_tree_page, 39662306a36Sopenharmony_ci .write_merkle_tree_block = ext4_write_merkle_tree_block, 39762306a36Sopenharmony_ci}; 398