@@ -87,3 +87,62 @@ bool netfs_encrypt(struct netfs_io_request *wreq)
wreq->error = ret;
return false;
}
+
+/*
+ * Decrypt the result of a read request.
+ */
+void netfs_decrypt(struct netfs_io_request *rreq)
+{
+ struct netfs_inode *ctx = netfs_inode(rreq->inode);
+ struct scatterlist source_sg[16], dest_sg[16];
+ unsigned int n_source;
+ size_t n, chunk, bsize = 1UL << ctx->crypto_bshift;
+ loff_t pos;
+ int ret;
+
+ trace_netfs_rreq(rreq, netfs_rreq_trace_decrypt);
+ if (rreq->start >= rreq->i_size)
+ return;
+
+ n = min_t(unsigned long long, rreq->len, rreq->i_size - rreq->start);
+
+ _debug("DECRYPT %llx-%llx f=%lx",
+ rreq->start, rreq->start + n, rreq->flags);
+
+ pos = rreq->start;
+ for (; n > 0; n -= chunk, pos += chunk) {
+ chunk = min(n, bsize);
+
+ ret = netfs_iter_to_sglist(&rreq->io_iter, chunk,
+ source_sg, ARRAY_SIZE(source_sg));
+ if (ret < 0)
+ goto error;
+ n_source = ret;
+
+ if (test_bit(NETFS_RREQ_CRYPT_IN_PLACE, &rreq->flags)) {
+ ret = ctx->ops->decrypt_block(rreq, pos, chunk,
+ source_sg, n_source,
+ source_sg, n_source);
+ } else {
+ ret = netfs_iter_to_sglist(&rreq->iter, chunk,
+ dest_sg, ARRAY_SIZE(dest_sg));
+ if (ret < 0)
+ goto error;
+ ret = ctx->ops->decrypt_block(rreq, pos, chunk,
+ source_sg, n_source,
+ dest_sg, ret);
+ }
+
+ if (ret < 0)
+ goto error_failed;
+ }
+
+ return;
+
+error_failed:
+ trace_netfs_failure(rreq, NULL, ret, netfs_fail_decryption);
+error:
+ rreq->error = ret;
+ set_bit(NETFS_RREQ_FAILED, &rreq->flags);
+ return;
+}
@@ -26,6 +26,7 @@ int netfs_prefetch_for_write(struct file *file, struct folio *folio,
* crypto.c
*/
bool netfs_encrypt(struct netfs_io_request *wreq);
+void netfs_decrypt(struct netfs_io_request *rreq);
/*
* direct_write.c
@@ -398,6 +398,9 @@ static void netfs_rreq_assess(struct netfs_io_request *rreq, bool was_async)
return;
}
+ if (!test_bit(NETFS_RREQ_FAILED, &rreq->flags) &&
+ test_bit(NETFS_RREQ_CONTENT_ENCRYPTION, &rreq->flags))
+ netfs_decrypt(rreq);
if (rreq->origin != NETFS_DIO_READ)
netfs_rreq_unlock_folios(rreq);
else
@@ -427,7 +430,8 @@ static void netfs_rreq_work(struct work_struct *work)
static void netfs_rreq_terminated(struct netfs_io_request *rreq,
bool was_async)
{
- if (test_bit(NETFS_RREQ_INCOMPLETE_IO, &rreq->flags) &&
+ if ((test_bit(NETFS_RREQ_INCOMPLETE_IO, &rreq->flags) ||
+ test_bit(NETFS_RREQ_CONTENT_ENCRYPTION, &rreq->flags)) &&
was_async) {
if (!queue_work(system_unbound_wq, &rreq->work))
BUG();
@@ -326,6 +326,9 @@ struct netfs_request_ops {
int (*encrypt_block)(struct netfs_io_request *wreq, loff_t pos, size_t len,
struct scatterlist *source_sg, unsigned int n_source,
struct scatterlist *dest_sg, unsigned int n_dest);
+ int (*decrypt_block)(struct netfs_io_request *rreq, loff_t pos, size_t len,
+ struct scatterlist *source_sg, unsigned int n_source,
+ struct scatterlist *dest_sg, unsigned int n_dest);
};
/*
@@ -40,6 +40,7 @@
#define netfs_rreq_traces \
EM(netfs_rreq_trace_assess, "ASSESS ") \
EM(netfs_rreq_trace_copy, "COPY ") \
+ EM(netfs_rreq_trace_decrypt, "DECRYPT") \
EM(netfs_rreq_trace_done, "DONE ") \
EM(netfs_rreq_trace_encrypt, "ENCRYPT") \
EM(netfs_rreq_trace_free, "FREE ") \
@@ -75,6 +76,7 @@
#define netfs_failures \
EM(netfs_fail_check_write_begin, "check-write-begin") \
EM(netfs_fail_copy_to_cache, "copy-to-cache") \
+ EM(netfs_fail_decryption, "decryption") \
EM(netfs_fail_dio_read_short, "dio-read-short") \
EM(netfs_fail_dio_read_zero, "dio-read-zero") \
EM(netfs_fail_encryption, "encryption") \