]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
rgw: write RGW_ATTR_CRYPT_PREFETCH_ALIGN for AEAD ciphers
authorMatthew N. Heler <matthew.heler@hotmail.com>
Mon, 30 Mar 2026 23:44:36 +0000 (18:44 -0500)
committerMatthew N. Heler <matthew.heler@hotmail.com>
Wed, 20 May 2026 18:31:02 +0000 (13:31 -0500)
Store the plaintext and encrypted block sizes at upload time so
future cls prefetch ops can compute on-disk read ranges from
xattrs without instantiating a cipher.

Only written for size-expanding ciphers (GCM). CBC objects have
no attr — plaintext and ciphertext sizes are identical.

Signed-off-by: Matthew N. Heler <matthew.heler@hotmail.com>
src/rgw/driver/rados/rgw_rados.cc
src/rgw/rgw_common.h
src/rgw/rgw_crypt.cc

index b0abf4fd25a3a1a26ba847cd4fc6e803fc2389b4..a042c71355ae263d2c5ecddcbd25301719b5b7dd 100644 (file)
@@ -5299,6 +5299,7 @@ int RGWRados::copy_obj(RGWObjectCtx& src_obj_ctx,
     // Data is rewritten as a single stream; drop stale multipart boundaries
     attrs.erase(RGW_ATTR_CRYPT_PARTS);
     attrs.erase(RGW_ATTR_CRYPT_PART_NUMS);
+    attrs.erase(RGW_ATTR_CRYPT_PREFETCH_ALIGN);
     return copy_obj_data(dest_obj_ctx, owner, dest_bucket_info, dest_placement, read_op, obj_size - 1, dest_obj,
                          mtime, real_time(), attrs, olh_epoch, delete_at, petag, dp_factory, dpp, y);
   }
index cc86bce2c456683bf874aa0b3fa230b477a685fe..f69c934cd3b65614f3197588b429316427a1129e 100644 (file)
@@ -194,6 +194,7 @@ using ceph::crypto::MD5;
 #define RGW_ATTR_CRYPT_PART_NUMS RGW_ATTR_CRYPT_PREFIX "part-numbers"
 #define RGW_ATTR_CRYPT_SALT     RGW_ATTR_CRYPT_PREFIX "salt"
 #define RGW_ATTR_CRYPT_ORIGINAL_SIZE RGW_ATTR_CRYPT_PREFIX "original-size"
+#define RGW_ATTR_CRYPT_PREFETCH_ALIGN RGW_ATTR_CRYPT_PREFIX "prefetch-align"
 
 /* SSE-S3 Encryption Attributes */
 #define RGW_ATTR_BUCKET_ENCRYPTION_PREFIX RGW_ATTR_PREFIX "sse-s3."
index ad796021a978e916956518ac4b251cafd1819dd4..4fb2eef0d69979b479b8a5caa84eda25126bee11 100644 (file)
@@ -2016,6 +2016,25 @@ bool rgw_get_aead_decrypted_size(const DoutPrefixProvider* dpp,
 }
 
 
+/*
+ * Write RGW_ATTR_CRYPT_PREFETCH_ALIGN for size-expanding ciphers
+ * so cls/prefetch can compute on-disk read ranges from xattrs.
+ */
+static void maybe_write_prefetch_align(
+    BlockCrypt* block_crypt,
+    std::map<std::string, ceph::bufferlist>& attrs)
+{
+  if (!block_crypt) return;
+  size_t plain_bs = block_crypt->get_block_size();
+  size_t enc_bs = block_crypt->get_encrypted_block_size();
+  if (enc_bs > plain_bs) {
+    bufferlist bl;
+    encode(static_cast<uint32_t>(plain_bs), bl);
+    encode(static_cast<uint32_t>(enc_bs), bl);
+    attrs[RGW_ATTR_CRYPT_PREFETCH_ALIGN] = std::move(bl);
+  }
+}
+
 int rgw_s3_prepare_encrypt(req_state* s, optional_yield y,
                            std::map<std::string, ceph::bufferlist>& attrs,
                            std::unique_ptr<BlockCrypt>* block_crypt,
@@ -2106,6 +2125,13 @@ int rgw_s3_prepare_encrypt(req_state* s, optional_yield y,
 
       if (use_gcm) {
         set_attr(attrs, RGW_ATTR_CRYPT_MODE, "SSE-C-AES256-GCM");
+        if (!block_crypt) {
+          // multipart-init: write prefetch align from AEAD constants
+          bufferlist align_bl;
+          encode(static_cast<uint32_t>(AEAD_CHUNK_SIZE), align_bl);
+          encode(static_cast<uint32_t>(AEAD_ENCRYPTED_CHUNK_SIZE), align_bl);
+          attrs[RGW_ATTR_CRYPT_PREFETCH_ALIGN] = std::move(align_bl);
+        }
         std::string salt = generate_gcm_salt(s, attrs);
         set_gcm_plaintext_size(s, attrs, is_copy);
 
@@ -2141,6 +2167,8 @@ int rgw_s3_prepare_encrypt(req_state* s, optional_yield y,
         }
       }
 
+      if (block_crypt && *block_crypt)
+        maybe_write_prefetch_align(block_crypt->get(), attrs);
       crypt_http_responses["x-amz-server-side-encryption-customer-algorithm"] = "AES256";
       crypt_http_responses["x-amz-server-side-encryption-customer-key-MD5"] = std::string(keymd5);
       return 0;
@@ -2218,6 +2246,12 @@ int rgw_s3_prepare_encrypt(req_state* s, optional_yield y,
 
         if (use_gcm) {
           set_attr(attrs, RGW_ATTR_CRYPT_MODE, "SSE-KMS-GCM");
+          if (!block_crypt) {
+            bufferlist align_bl;
+            encode(static_cast<uint32_t>(AEAD_CHUNK_SIZE), align_bl);
+            encode(static_cast<uint32_t>(AEAD_ENCRYPTED_CHUNK_SIZE), align_bl);
+            attrs[RGW_ATTR_CRYPT_PREFETCH_ALIGN] = std::move(align_bl);
+          }
           std::string salt = generate_gcm_salt(s, attrs);
           set_gcm_plaintext_size(s, attrs, is_copy);
 
@@ -2258,6 +2292,8 @@ int rgw_s3_prepare_encrypt(req_state* s, optional_yield y,
         ::ceph::crypto::zeroize_for_security(actual_key.data(), actual_key.length());
 
         crypt_http_responses["x-amz-server-side-encryption"] = "aws:kms";
+        if (block_crypt && *block_crypt)
+          maybe_write_prefetch_align(block_crypt->get(), attrs);
         crypt_http_responses["x-amz-server-side-encryption-aws-kms-key-id"] = std::string(key_id);
         crypt_http_responses["x-amz-server-side-encryption-context"] = std::move(cooked_context);
         return 0;
@@ -2308,6 +2344,12 @@ int rgw_s3_prepare_encrypt(req_state* s, optional_yield y,
 
       if (use_gcm) {
         set_attr(attrs, RGW_ATTR_CRYPT_MODE, "AES256-GCM");
+        if (!block_crypt) {
+          bufferlist align_bl;
+          encode(static_cast<uint32_t>(AEAD_CHUNK_SIZE), align_bl);
+          encode(static_cast<uint32_t>(AEAD_ENCRYPTED_CHUNK_SIZE), align_bl);
+          attrs[RGW_ATTR_CRYPT_PREFETCH_ALIGN] = std::move(align_bl);
+        }
         std::string salt = generate_gcm_salt(s, attrs);
         set_gcm_plaintext_size(s, attrs, is_copy);
 
@@ -2347,6 +2389,8 @@ int rgw_s3_prepare_encrypt(req_state* s, optional_yield y,
       }
       ::ceph::crypto::zeroize_for_security(actual_key.data(), actual_key.length());
 
+      if (block_crypt && *block_crypt)
+        maybe_write_prefetch_align(block_crypt->get(), attrs);
       crypt_http_responses["x-amz-server-side-encryption"] = "AES256";
 
       return 0;
@@ -2373,6 +2417,12 @@ int rgw_s3_prepare_encrypt(req_state* s, optional_yield y,
 
       if (use_gcm) {
         set_attr(attrs, RGW_ATTR_CRYPT_MODE, "RGW-AUTO-GCM");
+        if (!block_crypt) {
+          bufferlist align_bl;
+          encode(static_cast<uint32_t>(AEAD_CHUNK_SIZE), align_bl);
+          encode(static_cast<uint32_t>(AEAD_ENCRYPTED_CHUNK_SIZE), align_bl);
+          attrs[RGW_ATTR_CRYPT_PREFETCH_ALIGN] = std::move(align_bl);
+        }
         std::string salt = generate_gcm_salt(s, attrs);
         set_gcm_plaintext_size(s, attrs, is_copy);
 
@@ -2420,6 +2470,8 @@ int rgw_s3_prepare_encrypt(req_state* s, optional_yield y,
         }
         ::ceph::crypto::zeroize_for_security(actual_key, sizeof(actual_key));
       }
+      if (block_crypt && *block_crypt)
+        maybe_write_prefetch_align(block_crypt->get(), attrs);
       return 0;
     }
   }