]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
client: fscrypt last block
authorChristopher Hoffman <choffman@redhat.com>
Thu, 16 Jan 2025 23:37:51 +0000 (23:37 +0000)
committerChristopher Hoffman <choffman@redhat.com>
Wed, 5 Nov 2025 13:59:34 +0000 (13:59 +0000)
Support two edge cases in fscrypt last block.

1. When fscrypt last block is not the first block
2. Make sure to clean up SaferCond, allowing for successive
   truncates utilizing lastblock.

Signed-off-by: Christopher Hoffman <choffman@redhat.com>
src/client/Client.cc

index 4f1fdf3b7f4c1916de9e85b44918da1a2e0b376c..73c93b8efdff398ef85a4612e46f3a7b67332e6d 100644 (file)
@@ -8589,27 +8589,35 @@ int Client::_do_setattr(Inode *in, struct ceph_statx *stx, int mask,
     }
 
     ldout(cct,10) << "changing size to " << stx_size << dendl;
-    // client portion for fscrypt last block
+
+    //fscrypt last block
     //
-    // last block is only needed when truncating smaller
-    // and truncate size is non-zero.
+    //last block is only needed when truncating smaller
+    //when size is not aligned to FSCRYPT_BLOCK_SIZE
+    //and truncate size is non-zero.
     if (in->is_fscrypt_enabled() && stx_size < in->effective_size() &&
+        stx_size % FSCRYPT_BLOCK_SIZE != 0 &&
         (mask & CEPH_SETATTR_FSCRYPT_FILE) && stx_size != 0){
       // steps:
       // 1. read last block
-      int      offset;
-      offset = fscrypt_block_start(stx->stx_size);
 
+      //As we need to read the whole fscrypt block, derive
+      //offset from the new size.
+      int offset = fscrypt_block_start(stx->stx_size);
       bufferlist bl;
       bufferlist ebl;
       ceph_fscrypt_last_block_header header;
 
       int r;
-      C_SaferCond onfinish("Client::_read_sync flock");
+      std::unique_ptr<Context> io_finish = nullptr;
 
       uint64_t read_start;
       uint64_t read_len;
 
+      C_SaferCond *io_finish_cond = nullptr;
+      io_finish_cond = new C_SaferCond("Client::_read_async flock");
+      io_finish.reset(io_finish_cond);
+
       FSCryptFDataDencRef fscrypt_denc;
       fscrypt->prepare_data_read(in->fscrypt_ctx,
                                  &in->fscrypt_key_validator,
@@ -8617,36 +8625,46 @@ int Client::_do_setattr(Inode *in, struct ceph_statx *stx, int mask,
                                  &read_start, &read_len,
                                  &fscrypt_denc);
 
-
-      FSCryptFDataDencRef denc = fscrypt->get_fdata_denc(in->fscrypt_ctx, &in->fscrypt_key_validator);
+      get_cap_ref(in, CEPH_CAP_FILE_CACHE);
       std::vector<ObjectCacher::ObjHole> holes;
+      auto target_len = std::min(read_len, stx->stx_size - offset);
       r = objectcacher->file_read_ex(&in->oset, &in->layout, in->snapid,
-                                     read_start, read_len, &bl, 0, &holes, &onfinish);
+                                     read_start, target_len, &bl, 0, &holes, io_finish.get());
+
+      if (r == 0) {
+        client_lock.unlock();
+        r = io_finish_cond->wait();
+        client_lock.lock();
+      }
+      put_cap_ref(in, CEPH_CAP_FILE_CACHE);
+
+      header.ver = 1;
+      header.compat = 1;
+      header.change_attr = in->change_attr;
+      header.block_size = FSCRYPT_BLOCK_SIZE;
+
       if (bl.length() == 0) {
-       //this is a hole
-        header.data_len = (8 + 8 + 4);
+        //this is a hole
+       header.data_len = (8 + 8 + 4);
        header.file_offset = 0;
       } else {
-        r = denc->decrypt_bl(offset, stx->stx_size, read_start, holes, &bl);
+        r = fscrypt_denc->decrypt_bl(offset, target_len, read_start, holes, &bl);
+
         if (r < 0) {
           ldout(cct, 20) << __func__ << "(): failed to decrypt buffer: r=" << r << dendl;
           return r;
         }
 
        // 2. encrypt bl
-        if (denc)
-          r = denc->encrypt_bl(offset, bl.length(), bl, &ebl);
-
-        // 3. prepare lastblockbl
-        // TODO: support hole
-        header.ver = 1;
-        header.compat = 1;
-        header.change_attr = in->change_attr;
-        header.block_size = FSCRYPT_BLOCK_SIZE;
+        if (fscrypt_denc) {
+          r = fscrypt_denc->encrypt_bl(offset, bl.length(), bl, &ebl);
+       }
+
         header.data_len = (8 + 8 + 4 + ebl.length());
         header.file_offset = offset;
       }
 
+      // 3. prepare lastblockbl
       ENCODE_START(1, 1, lastblockbl);
       encode(header.change_attr, lastblockbl);
       encode(header.file_offset, lastblockbl);
@@ -11744,7 +11762,7 @@ void Client::C_Read_Async_Finisher::finish(int r)
 int Client::_read_async(Fh *f, uint64_t off, uint64_t len, bufferlist *bl,
                        Context *onfinish)
 {
-  (ceph_mutex_is_locked_by_me(client_lock));
+  ceph_assert(ceph_mutex_is_locked_by_me(client_lock));
 
   const auto& conf = cct->_conf;
   Inode *in = f->inode.get();