]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-ci.git/commitdiff
client: Use nearest fscrypt block when clamping max io size
authorChristopher Hoffman <choffman@redhat.com>
Mon, 20 Oct 2025 18:15:11 +0000 (18:15 +0000)
committerChristopher Hoffman <choffman@redhat.com>
Wed, 5 Nov 2025 13:59:36 +0000 (13:59 +0000)
A max io size can currently be up to INT_MAX. If it is greater,
then clamp the size to INT_MAX. This conflicts with fscrypt io
operations. An fscrypt, op needs to read a whole fscrypt block.
The size of fscrypt block size is 4K, INT_MAX % 4K is not equal
to 0. Therefore, get the nearest multiple of 4K to INT_MAX that
does not go over. In the fscrypt case, this value will be used
for clamping max io size.

Fixes: https://tracker.ceph.com/issues/73346
Signed-off-by: Christopher Hoffman <choffman@redhat.com>
src/client/Client.cc
src/client/FSCrypt.h

index de3626862a4818af1f45bc0bbbba203ce1344e6f..d865dd7c4f68d0c441b96648f78541f3fe0feac5 100644 (file)
@@ -11315,8 +11315,18 @@ int Client::read(int fd, char *buf, loff_t size, loff_t offset)
     return -EBADF;
 #endif
   bufferlist bl;
-  /* We can't return bytes written larger than INT_MAX, clamp size to that */
+#if defined(__linux__)
+  /* We can't return bytes written larger than INT_MAX, clamp size to
+   * that or FSCRYPT_MAXIO_SIZE*/
+  Inode *in = f->inode.get();
+  if (in->is_fscrypt_enabled()) {
+    size = std::min(size, (loff_t)FSCRYPT_MAXIO_SIZE);
+  } else {
+    size = std::min(size, (loff_t)INT_MAX);
+  }
+#else
   size = std::min(size, (loff_t)INT_MAX);
+#endif
   int r = _read(f, offset, size, &bl);
   ldout(cct, 3) << "read(" << fd << ", " << (void*)buf << ", " << size << ", " << offset << ") = " << r << dendl;
   if (r >= 0) {
@@ -12017,8 +12027,18 @@ int Client::write(int fd, const char *buf, loff_t size, loff_t offset)
   if (fh->flags & O_PATH)
     return -EBADF;
 #endif
-  /* We can't return bytes written larger than INT_MAX, clamp size to that */
+#if defined(__linux__)
+  /* We can't return bytes written larger than INT_MAX, clamp size to
+   * that or FSCRYPT_MAXIO_SIZE*/
+  Inode *in = fh->inode.get();
+  if (in->is_fscrypt_enabled()) {
+    size = std::min(size, (loff_t)FSCRYPT_MAXIO_SIZE);
+  } else {
+    size = std::min(size, (loff_t)INT_MAX);
+  }
+#else
   size = std::min(size, (loff_t)INT_MAX);
+#endif
   bufferlist bl;
   bl.append(buf, size);
   int r = _write(fh, offset, size, std::move(bl));
@@ -12058,7 +12078,18 @@ int64_t Client::_preadv_pwritev_locked(Fh *fh, const struct iovec *iov,
      */
     bufferlist data;
     if (clamp_to_int) {
+#if defined(__linux__)
+  /* We can't return bytes written larger than INT_MAX, clamp size to
+   * that or FSCRYPT_MAXIO_SIZE*/
+      Inode *in = fh->inode.get();
+      if (in->is_fscrypt_enabled()) {
+        totallen = std::min(totallen, (size_t)FSCRYPT_MAXIO_SIZE);
+      } else {
+        totallen = std::min(totallen, (size_t)INT_MAX);
+      }
+#else
       totallen = std::min(totallen, (size_t)INT_MAX);
+#endif
       size_t total_appended = 0;
       for (int i = 0; i < iovcnt; i++) {
         if (iov[i].iov_len > 0) {
@@ -16979,9 +17010,19 @@ int Client::ll_read(Fh *fh, loff_t off, loff_t len, bufferlist *bl)
     return -ENOTCONN;
   }
 
+#if defined(__linux__)
+  /* We can't return bytes written larger than INT_MAX, clamp size to
+   * that or FSCRYPT_MAXIO_SIZE*/
+  Inode *in = fh->inode.get();
+  if (in->is_fscrypt_enabled()) {
+    len = std::min(len, (loff_t)FSCRYPT_MAXIO_SIZE);
+  } else {
   /* We can't return bytes written larger than INT_MAX, clamp len to that */
+    len = std::min(len, (loff_t)INT_MAX);
+  }
+#else
   len = std::min(len, (loff_t)INT_MAX);
-
+#endif
   std::scoped_lock lock(client_lock);
   if (fh == NULL || !_ll_fh_exists(fh)) {
     ldout(cct, 3) << "(fh)" << fh << " is invalid" << dendl;
@@ -17124,9 +17165,18 @@ int Client::ll_write(Fh *fh, loff_t off, loff_t len, const char *data)
     return -ENOTCONN;
   }
 
-  /* We can't return bytes written larger than INT_MAX, clamp len to that */
+#if defined(__linux__)
+  /* We can't return bytes written larger than INT_MAX, clamp size to
+   * that or FSCRYPT_MAXIO_SIZE*/
+  Inode *in = fh->inode.get();
+  if (in->is_fscrypt_enabled()) {
+    len = std::min(len, (loff_t)FSCRYPT_MAXIO_SIZE);
+  } else {
+    len = std::min(len, (loff_t)INT_MAX);
+  }
+#else
   len = std::min(len, (loff_t)INT_MAX);
-
+#endif
   std::scoped_lock lock(client_lock);
   if (fh == NULL || !_ll_fh_exists(fh)) {
     ldout(cct, 3) << "(fh)" << fh << " is invalid" << dendl;
index 30b5a0300a3d77afe7499161f2ac23174f17db37..97baee7fdb543e2995f8ff7cd854aa265ce4634c 100644 (file)
 
 #define FSCRYPT_DATA_ALIGNMENT 16
 
+// fscrypt maxio_size cannot be INT_MAX as it is not a multiple of fscrypt
+// block size. Set it to nearest fscrypt block without exceeding INT_MAX
+#define FSCRYPT_MAXIO_SIZE fscrypt_block_start(INT_MAX)
+
 static inline uint64_t fscrypt_align_ofs(uint64_t ofs) {
   return (ofs + FSCRYPT_DATA_ALIGNMENT - 1) & ~(FSCRYPT_DATA_ALIGNMENT - 1);
 }