+#ifdef CONFIG_LL_ENCRYPTION
+/**
+ * osc_encrypt_pagecache_blocks() - overlay to llcrypt_encrypt_pagecache_blocks
+ * @srcpage: The locked pagecache page containing the block(s) to encrypt
+ * @dstpage: The page to put encryption result
+ * @len: Total size of the block(s) to encrypt. Must be a nonzero
+ * multiple of the filesystem's block size.
+ * @offs: Byte offset within @page of the first block to encrypt. Must be
+ * a multiple of the filesystem's block size.
+ * @gfp_flags: Memory allocation flags
+ *
+ * This overlay function is necessary to be able to provide our own bounce page.
+ */
+static struct page *osc_encrypt_pagecache_blocks(struct page *srcpage,
+ struct page *dstpage,
+ unsigned int len,
+ unsigned int offs,
+ gfp_t gfp_flags)
+
+{
+ const struct inode *inode = srcpage->mapping->host;
+ const unsigned int blockbits = inode->i_blkbits;
+ const unsigned int blocksize = 1 << blockbits;
+ u64 lblk_num = ((u64)srcpage->index << (PAGE_SHIFT - blockbits)) +
+ (offs >> blockbits);
+ unsigned int i;
+ int err;
+
+ if (unlikely(!dstpage))
+ return llcrypt_encrypt_pagecache_blocks(srcpage, len, offs,
+ gfp_flags);
+
+ if (WARN_ON_ONCE(!PageLocked(srcpage)))
+ return ERR_PTR(-EINVAL);
+
+ if (WARN_ON_ONCE(len <= 0 || !IS_ALIGNED(len | offs, blocksize)))
+ return ERR_PTR(-EINVAL);
+
+ /* Set PagePrivate2 for disambiguation in
+ * osc_finalize_bounce_page().
+ * It means cipher page was not allocated by llcrypt.
+ */
+ SetPagePrivate2(dstpage);
+
+ for (i = offs; i < offs + len; i += blocksize, lblk_num++) {
+ err = llcrypt_encrypt_block(inode, srcpage, dstpage, blocksize,
+ i, lblk_num, gfp_flags);
+ if (err)
+ return ERR_PTR(err);
+ }
+ SetPagePrivate(dstpage);
+ set_page_private(dstpage, (unsigned long)srcpage);
+ return dstpage;
+}
+
+/**
+ * osc_finalize_bounce_page() - overlay to llcrypt_finalize_bounce_page
+ *
+ * This overlay function is necessary to handle bounce pages
+ * allocated by ourselves.
+ */
+static inline void osc_finalize_bounce_page(struct page **pagep)
+{
+ struct page *page = *pagep;
+
+ ClearPageChecked(page);
+ /* PagePrivate2 was set in osc_encrypt_pagecache_blocks
+ * to indicate the cipher page was allocated by ourselves.
+ * So we must not free it via llcrypt.
+ */
+ if (unlikely(!page || !PagePrivate2(page)))
+ return llcrypt_finalize_bounce_page(pagep);
+
+ if (llcrypt_is_bounce_page(page)) {
+ *pagep = llcrypt_pagecache_page(page);
+ ClearPagePrivate2(page);
+ set_page_private(page, (unsigned long)NULL);
+ ClearPagePrivate(page);
+ }
+}
+#else /* !CONFIG_LL_ENCRYPTION */
+#define osc_encrypt_pagecache_blocks(srcpage, dstpage, len, offs, gfp_flags) \
+ llcrypt_encrypt_pagecache_blocks(srcpage, len, offs, gfp_flags)
+#define osc_finalize_bounce_page(page) llcrypt_finalize_bounce_page(page)
+#endif
+